Skip to content

Add RelativeUri enum for types of relative links#2078

Merged
thomas-zahner merged 16 commits into
lycheeverse:masterfrom
rina-forks:relative-link-kind
Mar 18, 2026
Merged

Add RelativeUri enum for types of relative links#2078
thomas-zahner merged 16 commits into
lycheeverse:masterfrom
rina-forks:relative-link-kind

Conversation

@katrinafyi

Copy link
Copy Markdown
Member

This adds an enum:

pub enum RelativeUri<'a> {
    /// A root-relative link, e.g. `"/help"`. The contained string will
    /// start with `/` and not start with `//`.
    RootRel(&'a str),
    /// A scheme-relative link, e.g. `"//example.comhelp"`. The contained
    /// string will start with `//`.
    SchemeRel(&'a str),
    /// A locally-relative link, e.g. `"help"` or `"../home"`.
    LocalRel(&'a str),
}

This lets us cleans up some logic that depended on the relative link kind, and it lets us use a more explicit match in BaseInfo.

@thomas-zahner thomas-zahner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR! Looks pretty great 🚀

Comment thread lychee-lib/src/types/uri/relative.rs Outdated
Comment thread lychee-lib/src/types/uri/relative.rs Outdated
Comment thread lychee-lib/src/types/uri/relative.rs Outdated
Comment thread lychee-lib/src/types/base_info.rs Outdated
Comment thread lychee-lib/src/types/base_info.rs Outdated
Comment thread lychee-lib/src/types/uri/relative.rs Outdated
Co-authored-by: Thomas Zahner <thomas.zahner@protonmail.ch>

@katrinafyi katrinafyi left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review!

Comment thread lychee-lib/src/types/base_info.rs Outdated
Comment thread lychee-lib/src/types/base_info.rs Outdated
Comment thread lychee-lib/src/types/uri/relative.rs Outdated

@katrinafyi katrinafyi left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I've replied to all of the comments so far :)

Comment thread lychee-lib/src/types/base_info.rs Outdated
Comment thread lychee-lib/src/types/uri/relative.rs Outdated
Comment thread lychee-lib/src/types/base_info.rs Outdated
Comment thread lychee-lib/src/types/uri/relative.rs Outdated
Comment thread lychee-lib/src/types/uri/relative.rs Outdated
@mre

mre commented Mar 14, 2026

Copy link
Copy Markdown
Member

I’d like to suggest a refactor for parse_url_or_relative following the "parse, don't validate" pattern.

By introducing a Link type, we can remove the dependency on either and replace parse_url_text with a resolve_to method. This consolidates the prefix logic into a single pass.

pub enum Link<'a> {
    Absolute(Uri),
    Relative(RelativeUri<'a>),
}

impl<'a> Link<'a> {
    pub fn parse(text: &'a str) -> Result<Self, ErrorKind> {
        let text = text.trim_ascii_start();
        match Uri::try_from(text) {
            Ok(uri) => Ok(Self::Absolute(uri)),
            Err(ErrorKind::ParseUrl(ParseError::RelativeUrlWithoutBase, _)) => {
                let rel = if text.starts_with("//") {
                    RelativeUri::Scheme(text)
                } else if text.starts_with('/') {
                    RelativeUri::Root(text)
                } else {
                    RelativeUri::Local(text)
                };
                Ok(Self::Relative(rel))
            }
            Err(e) => Err(e),
        }
    }

    pub fn resolve_to(self, base: &BaseInfo) -> Result<Url, ErrorKind> {
        match self {
            Self::Absolute(uri) => Ok(uri.url),
            Self::Relative(rel) => base.resolve_relative_link(&rel),
        }
    }
}

Not too happy with the term Link. We could also call it InputUri or something.
And parse could also be a TryFrom, but you get the idea.

Does this make sense? Sorry, not too deep into that topic, so there's a high chance I'm missing important context.

@katrinafyi

katrinafyi commented Mar 15, 2026

Copy link
Copy Markdown
Member Author

Parse don't validate (PDV) is about encoding properties that have been checked into the type itself and avoiding overly general types like String.

The refactor you suggested doesn't increase PDV, because it's the same quantity of information just in different names (but if you do want different names, we can do that).

In fact, both my current code and your suggestion fall afoul of "names are not type safety" because we've just given a name to &str without constraining what's inside the string.

As you noted, the slicing &x[1..] could panic on general strings. But it was my intention (and I wrote in the doc comments) that SchemeRel should always start with //, so this should be safe. But this is an example of a validated, not parsed, property so it's not guaranteed in the types.

If we were to increase PDV, that would look like replacing the &str inside SchemeRel with a specific type that knows it always starts with //. Something like SchemeRel(StrWithPrefix<'a, "//">) - using const generic parameters. This would give us more safety and guarantees.

This could be done using something like refinement types - specifically, a StartsWith predicate. Or, if that's too heavy, I can write a basic type myself. Or, we just use unwrap_or :)

@mre

mre commented Mar 16, 2026

Copy link
Copy Markdown
Member

You're right. Let's dismiss that idea. So the only open point from my side would be #2078 (comment).

Comment thread lychee-lib/src/types/uri/parsed.rs
Comment thread lychee-lib/src/types/uri/relative.rs Outdated
katrinafyi and others added 3 commits March 17, 2026 23:46
Co-authored-by: Thomas Zahner <thomas.zahner@protonmail.ch>
everyone should use RelativeUri::new if they want to discriminate on relative link types.
@thomas-zahner thomas-zahner merged commit c282f13 into lycheeverse:master Mar 18, 2026
7 checks passed
@mre mre mentioned this pull request Mar 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants