Open vlovich opened 5 months ago
You may need to add generic implementation for this smartpointer.
Look at implementation for Box
Where do I find the implementation? The only place Box comes up as a string in the code is in the roundtrip
test.
Not sure if it's the cleanest way but here's what I came up with. The annoying bit is that any struct that uses RcBox<T>
is managed. The other problem is that deserialize_in_place
is on the same trait as deserialize
which means I can't define deserialize and a separate deserialize_in_place
that requires T: Default
, so I have to return an error.
#[derive(Formula)]
struct RcFormula<T>(T);
impl<T: SerializeRef<T> + Formula> SerializeRef<RcFormula<T>> for std::rc::Rc<T> {
fn serialize<B>(
&self,
sizes: &mut alkahest::advanced::Sizes,
buffer: B,
) -> std::result::Result<(), B::Error>
where
B: alkahest::advanced::Buffer,
{
<T as SerializeRef<T>>::serialize(self.as_ref(), sizes, buffer)
}
fn size_hint(&self) -> Option<alkahest::advanced::Sizes> {
<T as SerializeRef<T>>::size_hint(self.as_ref())
}
}
impl<T: Serialize<T> + Formula> Serialize<RcFormula<T>> for std::rc::Rc<T> {
fn serialize<B>(
self,
sizes: &mut alkahest::advanced::Sizes,
buffer: B,
) -> std::result::Result<(), B::Error>
where
B: alkahest::advanced::Buffer,
{
if let Some(inner) = std::rc::Rc::into_inner(self) {
<T as Serialize<T>>::serialize(inner, sizes, buffer)
} else {
panic!("Not a unique reference and can't return an error?")
}
}
fn size_hint(&self) -> Option<alkahest::advanced::Sizes> {
<T as Serialize<T>>::size_hint(self.as_ref())
}
}
impl<'de, T: Deserialize<'de, T> + Formula> Deserialize<'de, RcFormula<T>> for std::rc::Rc<T> {
fn deserialize(
deserializer: alkahest::advanced::Deserializer<'de>,
) -> std::result::Result<Self, alkahest::DeserializeError>
where
Self: Sized,
{
Ok(std::rc::Rc::new(<T as Deserialize<T>>::deserialize(
deserializer,
)?))
}
fn deserialize_in_place(
&mut self,
_deserializer: alkahest::advanced::Deserializer<'de>,
) -> std::result::Result<(), alkahest::DeserializeError> {
// T might not implement Default so there's no way to get a &mut T from self.
Err(alkahest::DeserializeError::Incompatible)
}
}
I've added implementation for Box, Rc and Arc in https://github.com/zakarumych/alkahest/commit/7a45d2649b08f4ecf2a8a756be860a05e0545888
Ow wow! Did not know expect that, thanks! I also may have 3p smart pointers (eg I use hybrid_rc although not sure it'll come up here necessarily). I'm assuming there's no good way to do this generically since I can't impl Serialize/Deserialize for external crates, so I'll need to write wrappers or explicit formulas instead?
Take note that Box cannot be a generic Formula
due to being #[fundamental]
which allows downstream crates to implement Formula
for Box<DownstreamCrateLocalType>
and this causes potential conflict disallowed by Rust.
So if you need to serialize Box<T>
field you'll need a separate type to derive Formula
where field is just F
where T: Serialize<F>
.
Like this:
#[derive(alkahest_proc::Formula)]
struct Foo {
a: u32,
}
#[alkahest(SerializeRef<Foo>, Deserialize<'_, Foo>)]
struct FooWithBox {
a: Box<u32>,
}
hybrid_rc
You can add impls to this crate with optional dependency
Or in their crate instead :)
If I want to have a Serialize that contains an Rc<Vec>, is there a way to do this?