Repository: leptos-rs/leptos
File: router_macro/src/lib.rs (Rust)

Code before:
            }
        }
    }

    pub fn parse_str(segments: &mut Vec<Segment>, current_str: &str) {
        if ["", "*"].contains(&current_str) {
            return;
        }

        for segment in current_str.split('/') {
            if let Some(segment) = segment.strip_prefix(':') {
                segments.push(Segment::Param(segment.to_string()));
            } else if let Some(segment) = segment.strip_prefix('*') {
                segments.push(Segment::Wildcard(segment.to_string()));
            } else {
                segments.push(Segment::Static(segment.to_string()));
            }
        }
    }
}

impl Segment {
    fn is_valid(segment: &str) -> bool {
        segment
            .chars()
            .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')
    }

    fn ensure_valid(&self) {
        match self {
            Self::Wildcard(s) if !Self::is_valid(s) => {
                abort!(Span::call_site(), "Invalid wildcard segment: {}", s)
            }
            Self::Static(s) if !Self::is_valid(s) => {
                abort!(Span::call_site(), "Invalid static segment: {}", s)
            }
            Self::Param(s) if !Self::is_valid(s) => {
                abort!(Span::call_site(), "Invalid param segment: {}", s)
            }
            _ => (),
        }
    }
}

impl Segments {
    fn ensure_valid(&self) {
        if let Some((_last, segments)) = self.0.split_last() {
            if let Some(Segment::Wildcard(s)) =
                segments.iter().find(|s| matches!(s, Segment::Wildcard(_)))
            {
                abort!(Span::call_site(), "Wildcard must be at end: {}", s)

Review comment (bug):
I'm wondering if this is slightly too restrictive — for example, I'd think `_` should be a valid character for static segments, at least, and possibly other [rarer but spec-compliant characters](https://stackoverflow.com/questions/4669692/valid-characters-for-directory-part-of-a-url-for-short-links).

Code after:
                TokenTree::Group(_) => unimplemented!(),
                TokenTree::Ident(_) => unimplemented!(),
                TokenTree::Punct(_) => unimplemented!(),
            }
        }
    }

    pub fn parse_str(segments: &mut Vec<Segment>, current_str: &str) {
        if ["", "*"].contains(&current_str) {
            return;
        }

        for segment in current_str.split('/') {
            if let Some(segment) = segment.strip_prefix(':') {
                segments.push(Segment::Param(segment.to_string()));
            } else if let Some(segment) = segment.strip_prefix('*') {
                segments.push(Segment::Wildcard(segment.to_string()));
            } else {
                segments.push(Segment::Static(segment.to_string()));
            }
        }
    }
}

impl Segment {
    fn is_valid(segment: &str) -> bool {
        segment.chars().all(|c| {
            c.is_ascii_digit()
                || c.is_ascii_lowercase()
                || c.is_ascii_uppercase()
                || RFC3986_UNRESERVED.contains(&c)
                || RFC3986_PCHAR_OTHER.contains(&c)
        })
    }

    fn ensure_valid(&self) {
        match self {
            Self::Wildcard(s) if !Self::is_valid(s) => {
                abort!(Span::call_site(), "Invalid wildcard segment: {}", s)
            }
            Self::Static(s) if !Self::is_valid(s) => {
                abort!(Span::call_site(), "Invalid static segment: {}", s)
            }
            Self::Param(s) if !Self::is_valid(s) => {
                abort!(Span::call_site(), "Invalid param segment: {}", s)
            }
            _ => (),
        }
    }
}