Support for borrowing newtypes
Ducky2048 opened this issue · 8 comments
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?
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
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!
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() })
}
}
@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.
@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>
)
@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.
@Ducky2048 That's very nice of you! Thank you very much! ❤️
@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.