[Serde] serializing Rc<T> - weird problem with compiling

Hello!
I have a problem with compiling my code.

In Playground is OK, code is compiling (Build using the Stable version: 1.56.1).

On my PC (toolchain: 1.56.1-x86_64-unknown-linux-gnu) no, I have an error:

mhanusek@EtHanusek:~/ser-test$ cargo +1.56.1 b
   Compiling proc-macro2 v1.0.32
   Compiling unicode-xid v0.2.2
   Compiling syn v1.0.81
   Compiling autocfg v1.0.1
   Compiling serde_derive v1.0.130
   Compiling serde v1.0.130
   Compiling linked-hash-map v0.5.4
   Compiling hashbrown v0.11.2
   Compiling dtoa v0.4.8
   Compiling indexmap v1.7.0
   Compiling yaml-rust v0.4.5
   Compiling quote v1.0.10
   Compiling serde_yaml v0.8.21
   Compiling ser-test v0.1.0 (/home/mhanusek/work/VersionControl/ETDCS2/ser-test)
error[E0277]: the trait bound `Rc<FrameObject>: Serialize` is not satisfied
    --> src/main.rs:17:5
     |
17   |     pub frames: Vec<Rc<FrameObject>>,
     |     ^^^ the trait `Serialize` is not implemented for `Rc<FrameObject>`
     |
     = note: required because of the requirements on the impl of `Serialize` for `Vec<Rc<FrameObject>>`
note: required by `_::_serde::ser::SerializeStruct::serialize_field`
    --> /home/mhanusek/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.130/src/ser/mod.rs:1893:5
     |
1893 | /     fn serialize_field<T: ?Sized>(
1894 | |         &mut self,
1895 | |         key: &'static str,
1896 | |         value: &T,
1897 | |     ) -> Result<(), Self::Error>
1898 | |     where
1899 | |         T: Serialize;
     | |_____________________^

error[E0277]: the trait bound `Rc<FrameObject>: Deserialize<'_>` is not satisfied
    --> src/main.rs:17:5
     |
17   |     pub frames: Vec<Rc<FrameObject>>,
     |     ^^^ the trait `Deserialize<'_>` is not implemented for `Rc<FrameObject>`
     |
     = note: required because of the requirements on the impl of `Deserialize<'_>` for `Vec<Rc<FrameObject>>`
note: required by `next_element`
    --> /home/mhanusek/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.130/src/de/mod.rs:1703:5
     |
1703 | /     fn next_element<T>(&mut self) -> Result<Option<T>, Self::Error>
1704 | |     where
1705 | |         T: Deserialize<'de>,
     | |____________________________^

error[E0277]: the trait bound `Rc<FrameObject>: Deserialize<'_>` is not satisfied
    --> src/main.rs:17:5
     |
17   |     pub frames: Vec<Rc<FrameObject>>,
     |     ^^^ the trait `Deserialize<'_>` is not implemented for `Rc<FrameObject>`
     |
     = note: required because of the requirements on the impl of `Deserialize<'_>` for `Vec<Rc<FrameObject>>`
note: required by `next_value`
    --> /home/mhanusek/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.130/src/de/mod.rs:1842:5
     |
1842 | /     fn next_value<V>(&mut self) -> Result<V, Self::Error>
1843 | |     where
1844 | |         V: Deserialize<'de>,
     | |____________________________^

For more information about this error, try `rustc --explain E0277`.
error: could not compile `ser-test` due to 3 previous errors

https://serde.rs/feature-flags.html#-features-rc

1 Like

@steffahn thx.
Solution:

serde = { version = "1.0.130", features = ["derive", "rc"] }

Warning! Enabling this feature is dangerous, and it may not do what you actually intended!

The reason serializing and deserializing Rc (and Arc) is feature-gated in Serde is pretty important. An Rc represents shared ownership. You can have multiple Rc instances point to the same value. This is already problematic in itself: when you deserialize an Rc, serde will necessarily have to allocate new, distinct objects for backing each Rc, since it doesn't know which value came from which ref-counted pointer. This means that while you have a valid, deserialized Rc, you will necessarily lose object identity.

During the past few days, there has been a surge in questions related to object identity and data structures that implement equality by pointer identity. Such a data structure is guaranteed to be corrupted by round-tripping it through serde, which is Bad™.

Furthermore, you can create reference cycles using ref-counted pointers. Since serde expects serialized values to form a tree, serializing such cycles could either cause infinite recursion (for naïve implementations of a serialization format) and a stack overflow, or it could fail in a somewhat puzzling way (when the serializer sets a recursion limit).

3 Likes

Absolutely! In Rust, it is quite tempting to use a Rc<RefCell> as an escape-hatch from Rust's borrow check system. But in practice, there are more idiomatic and more efficient ways of solving such problems. Rc<RefCell> has it's use cases, but it's far less than what people with a C/C++ background (such as me) tend to think when we first learn Rust.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.