Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NoCustomError should be replaced by Infallible (or another empty enum) #3154

Closed
nicolas-guichard opened this issue Oct 23, 2024 · 5 comments
Closed

Comments

@nicolas-guichard
Copy link

When matching over a ServerFnError, we always have to cover the WrappedServerError case, even though it should not be used when CustErr = NoCustomError.

This happens because NoCustomError is an empty struct, which can be constructed.

Instead I think we should use an empty enum such as std::convert::Infallible, which would:

  • prevent from creating that variant altogether
  • remove the need to match for that variant (since Rust 1.82)

This would however be a breaking change.

@nicolas-guichard
Copy link
Author

If/when this is implemented, we could provide an infallible conversion from ServerFnError<NoCustomError> to ServerFnError<CustErr>:

impl<CustErr> From<ServerFnError<NoCustomError>> for ServerFnError<CustErr> {
    fn from(value: ServerFnError<NoCustomError>) -> Self {
        match self {
            // not needed since Rust 1.82 if NoCustomError becomes uninhabited:
            // ServerFnError::<NoCustomError>::WrappedServerError(_) => unreachable!(),
            ServerFnError::<NoCustomError>::Registration(s) => ServerFnError::<CustErr>::Registration(s),
            ServerFnError::<NoCustomError>::Request(s) => ServerFnError::<CustErr>::Request(s),
            ServerFnError::<NoCustomError>::Response(s) => ServerFnError::<CustErr>::Response(s),
            ServerFnError::<NoCustomError>::ServerError(s) => ServerFnError::<CustErr>::ServerError(s),
            ServerFnError::<NoCustomError>::Deserialization(s) => ServerFnError::<CustErr>::Deserialization(s),
            ServerFnError::<NoCustomError>::Serialization(s) => ServerFnError::<CustErr>::Serialization(s),
            ServerFnError::<NoCustomError>::Args(s) => ServerFnError::<CustErr>::Args(s),
            ServerFnError::<NoCustomError>::MissingArg(s) => ServerFnError::<CustErr>::MissingArg(s),
        }
    }
}

Currently to enable the ? operator, I parameterize the functions that return ServerFnError to take the CustError from their caller.

@gbj
Copy link
Collaborator

gbj commented Oct 23, 2024

Could you provide an example of the problem you're trying to solve?

@nicolas-guichard
Copy link
Author

For instance let's say I have a helper function like this:

pub fn auth() -> Result<AuthSession, ServerFnError> {
    use_context::<AuthSession>().ok_or_else(|| {
        ServerFnError::ServerError("Auth session missing.".into())
    })
}

I want to write this:

enum GetUsernameError {
    NotLoggedIn,
}

#[server]
pub async fn get_username() -> Result<Option<User>, ServerFnError<GetUsernameError>> {
    use crate::todo::ssr::auth;

    let auth = auth()?; // ← this currently fails, adding the From impl above solves that, and making NoCustomError uninhabited makes it infallible

    match auth.current_user {
        None => Err(GetUsernameError::NotLoggedIn.into()),
        Some(user) => Ok(user.name),
    }
}

If you don't have anything against those additions, I'll send PRs your way.

@gbj
Copy link
Collaborator

gbj commented Oct 24, 2024

Sure. Can't say I understand this one, but I have never used the custom errors so I am sure I will once I see a PR!

@benwis
Copy link
Contributor

benwis commented Nov 17, 2024

I understand this one, but expect it's not possible for us. If we replaced NoCustomError, which is an empty struct, with Infallible, we wouldn't be able to derive the traits we need for the orphan rule.

I'm going to close this, but if you can prove me wrong with a PR, that'd be great

@benwis benwis closed this as completed Nov 17, 2024
nicolas-guichard added a commit to nicolas-guichard/leptos that referenced this issue Nov 17, 2024
Contrary to an empty struct, which has exactly 1 possible value, an
empty enum has 0 possible values: it can't even be constructed.

Fixes leptos-rs#3154
nicolas-guichard added a commit to nicolas-guichard/leptos that referenced this issue Nov 17, 2024
Contrary to an empty struct, which has exactly 1 possible value, an
empty enum has 0 possible values: it can't even be constructed.

Fixes leptos-rs#3154
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

No branches or pull requests

3 participants