fn check_topic_filter()

in rust/azure_iot_operations_mqtt/src/topic.rs [220:285]


    fn check_topic_filter(topic_filter: &str) -> Result<(), TopicParseError> {
        let mut prev_ml_wildcard = false;
        let mut levels = topic_filter.split(LEVEL_SEPARATOR);
        let mut filter_levels_length = 0;
        // Used to check if the first level of the topic filter is empty to account for the case
        // where a shared subscription topic filter is used with an empty topic filter, i.e "$share/consumer1/"
        let mut first_topic_filter_level_empty = false;

        if is_shared_sub(topic_filter) {
            // Skip $share
            levels.next();
            // The ShareName MUST NOT contain the characters "/", "+" or "#", but MUST be followed by a "/" character. This "/" character MUST be followed by a Topic Filter (4.8.2)
            match levels.next() {
                Some(share_name) => {
                    if share_name.contains(MULTI_LEVEL_WILDCARD)
                        || share_name.contains(SINGLE_LEVEL_WILDCARD)
                        || share_name.is_empty()
                    {
                        return Err(TopicParseError::InvalidShareName(topic_filter.to_string()));
                    }
                }
                None => {
                    // No share name
                    return Err(TopicParseError::SharedSubscriptionTooShort(
                        topic_filter.to_string(),
                    ));
                }
            }
        }

        // NOTE: Adjacent topic filter level separators ("/") are valid and indicate a zero length topic level (4.7.1.1)
        // NOTE: Topic filters can contain the space (" ") character (4.7.3)
        for level in levels {
            filter_levels_length += 1;

            // Check if the first level of the topic filter is empty
            if filter_levels_length == 1 && level.is_empty() {
                first_topic_filter_level_empty = true;
            }

            if prev_ml_wildcard {
                // Multi-level wildcard MUST be the last character specified (4.7.1.2)
                return Err(TopicParseError::WildcardNotLast(topic_filter.to_string()));
            }
            if level.contains(MULTI_LEVEL_WILDCARD) {
                // Multi-level wildcard MUST occupy an entire level of the topic filter (4.7.1.2)
                if level != MULTI_LEVEL_WILDCARD {
                    return Err(TopicParseError::WildcardNotAlone(topic_filter.to_string()));
                }
                prev_ml_wildcard = true;
            }
            if level.contains(SINGLE_LEVEL_WILDCARD) {
                // Single-level wildcard MUST occupy an entire level of the topic filter (4.7.1.3)
                if level != SINGLE_LEVEL_WILDCARD {
                    return Err(TopicParseError::WildcardNotAlone(topic_filter.to_string()));
                }
            }
        }
        // Topic filters must be at least one character long (4.7.3)
        if filter_levels_length == 0
            || (first_topic_filter_level_empty && filter_levels_length == 1)
        {
            return Err(TopicParseError::Empty);
        }
        Ok(())
    }