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

Support for borrowing newtypes #133

Closed
Ducky2048 opened this issue Apr 15, 2024 · 8 comments
Closed

Support for borrowing newtypes #133

Ducky2048 opened this issue Apr 15, 2024 · 8 comments
Assignees

Comments

@Ducky2048
Copy link

First of all, thank you for this library! I like it a lot.

I have a request:

I would like to make newtypes containing borrowed values, but it appears that doesn't work.

For example, this:

#[nutype(derive(Debug))]
struct A<'a>(Cow<'a, str>);

Expands to this:

#[doc(hidden)]
mod __nutype_private_A__ {
    use super::*;

    #[derive(Debug, )]
   /// Lifetime on A is missing
    pub struct A(Cow<'a, str>);

    impl A {
        pub fn new(raw_value: Cow<'a, str>) -> Self {
            fn sanitize(mut value: Cow<'a, str>) -> Cow<'a, str> { value }
            Self(sanitize(raw_value))
        }
    }

    impl A { pub fn into_inner(self) -> Cow<'a, str> { self.0 } }
}
use __nutype_private_A__::A

The important part is that the lifetime declaration on A seems to be lost. Is it possible to make this work?

@Ducky2048 Ducky2048 changed the title Support for Cow Support for borrowing newtypes Apr 15, 2024
@greyblake
Copy link
Owner

Hi, thanks for reporting the issue.
Currently generics are not yet support, but I plan to add support for this.
There is a related issue to this: #130

@greyblake
Copy link
Owner

The basics implementation to support generics is merged in #135

There some corner cases that need to be addressed before a new version can be published, see generics label.

@Ducky2048 If would appreciate if you can try the current implementation out and let me know if there something else missing!

@Ducky2048
Copy link
Author

It works perfectly for what I initially asked for, which is great!

What I found is that automatically deriving Serialize and Deserialize doesn't seem to work:

#[nutype(
    derive(
        Debug,
        Serialize,
        Deserialize,
    ),
)]
pub struct Borrowing<'a>(Cow<'a, str>);

Expands to:

#[derive(Debug, )]
pub struct Borrowing<'a> (Cow<'a, str>);
// perfect
impl<'a> Borrowing<'a> {
    pub fn new(raw_value: Cow<'a, str>) -> Self { Self(Self::__sanitize__(raw_value)) }
    fn __sanitize__(mut value: Cow<'a, str>) -> Cow<'a, str> { value }
}

// also perfect
impl<'a> Borrowing<'a> {
    #[inline]
    pub fn into_inner(self) -> Cow<'a, str> { self.0 }
}

// missing lifetime
impl ::serde::Serialize for Borrowing { fn serialize<S>(&self, serializer: S) -> ::core::result::Result<S::Ok, S::Error> where S: ::serde::Serializer { serializer.serialize_newtype_struct("Borrowing", &self.0) } }

// missing lifetime
impl<'de> ::serde::Deserialize<'de> for Borrowing {
    fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        struct __Visitor<'de> {
            marker: ::std::marker::PhantomData<Borrowing>,
            lifetime: ::std::marker::PhantomData<&'de ()>,
        }
        impl<'de> ::serde::de::Visitor<'de> for __Visitor<'de> {
            type Value = Borrowing;
            fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { formatter.write_fmt(::core::format_args!("tuple struct Borrowing")) }
            fn visit_newtype_struct<DE>(self, deserializer: DE) -> Result<Self::Value, DE::Error> where DE: ::serde::Deserializer<'de> {
                let raw_value: Cow<'a, str> = match <Cow<'a, str> as ::serde::Deserialize>::deserialize(deserializer) {
                    Ok(val) => val,
                    Err(err) => return Err(err)
                };
                Ok(Borrowing::new(raw_value))
            }
        }
        ::serde::de::Deserializer::deserialize_newtype_struct(deserializer, "Borrowing", __Visitor { marker: Default::default(), lifetime: Default::default() })
    }
}

@greyblake
Copy link
Owner

@Ducky2048 Thanks for the feedback!
Some traits cannot be derived yet properly, here is issue for to make serde traits work with generics: #141
I hope to address rather sooner than later.

@greyblake
Copy link
Owner

greyblake commented Jun 3, 2024

@Ducky2048 Deserialize & Serialize for Cow<'a, str> should work (merged in #144).
Note, that it's not yet the full generics support for the serde traits (e.g. It won't yet work with things like NonEmpty<T>)

@Ducky2048
Copy link
Author

@greyblake Thanks a lot! I just donated 100 € for humanitarian aid to Ukraine. It's a miniscule amount in comparison to what the country needs, but maybe it helps just a little.

@greyblake
Copy link
Owner

greyblake commented Jun 4, 2024

@Ducky2048 That's very nice of you! Thank you very much! ❤️

@greyblake
Copy link
Owner

@Ducky2048 I just finished the work with generics and published 0.4.3-beta.1.
I am planning to release 0.4.3 in a week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Status: Done
Development

No branches or pull requests

2 participants