conjure_core/ast/
serde.rs

1//! Serde serialization/ deserialization helpers.
2//!
3//! These are used in combination with the
4//! [`serde_as`](https://docs.rs/serde_with/3.12.0/serde_with/index.html) annotation on AST types.
5
6use std::cell::RefCell;
7use std::rc::Rc;
8
9use serde::de::Deserialize;
10use serde::de::Error;
11use serde::Serialize;
12use serde_with::{DeserializeAs, SerializeAs};
13
14/// A unique id, used to distinguish between objects of the same type.
15///
16///
17/// This is used for pointer translation during (de)serialisation.
18pub type ObjId = u32;
19
20/// A type with an [`ObjectId`].
21///
22/// Each object of the implementing type has a unique id; however, ids are not unique for different
23/// type of objects.
24///
25/// Implementing types should ensure that the id is updated when an object is cloned.
26pub trait HasId {
27    /// The id of this object.
28    ///
29    /// Each object of this type has a unique id; however, ids are not unique for different type of
30    /// objects.
31    fn id(&self) -> ObjId;
32}
33
34/// A type that can be created with default values and an id.
35pub trait DefaultWithId: HasId {
36    /// Creates a new default value of type `T`, but with the given id.
37    fn default_with_id(id: ObjId) -> Self;
38}
39
40/// De/Serialize an `Rc<RefCell<T>>` as the id of the inner value `T`.
41///
42/// On de-serialization, each object is created as the default value for that type, except with the
43/// id's being retained.
44///
45/// It is left to the user to fix these values before use. Before serialization, each object in
46/// memory has a unique id; using this information, re-constructing the shared pointers should be
47/// possible, as long as the contents of each object were also stored, e.g. with
48/// [`RcRefCellAsInner`].
49pub struct RcRefCellAsId;
50
51// https://docs.rs/serde_with/3.12.0/serde_with/trait.SerializeAs.html#implementing-a-converter-type
52
53impl<T> SerializeAs<Rc<RefCell<T>>> for RcRefCellAsId
54where
55    T: HasId,
56{
57    fn serialize_as<S>(source: &Rc<RefCell<T>>, serializer: S) -> Result<S::Ok, S::Error>
58    where
59        S: serde::Serializer,
60    {
61        let id = (**source).borrow().id();
62        serializer.collect_str(&id)
63    }
64}
65
66// https://docs.rs/serde_with/3.12.0/serde_with/trait.DeserializeAs.html
67impl<'de, T> DeserializeAs<'de, Rc<RefCell<T>>> for RcRefCellAsId
68where
69    T: HasId + DefaultWithId,
70{
71    fn deserialize_as<D>(deserializer: D) -> Result<Rc<RefCell<T>>, D::Error>
72    where
73        D: serde::Deserializer<'de>,
74    {
75        let id = u32::deserialize(deserializer).map_err(Error::custom)?;
76        Ok(Rc::new(RefCell::new(T::default_with_id(id))))
77    }
78}
79
80/// De/Serialize an `Rc<RefCell<T>>` as its inner value `T`.
81///
82/// This makes no attempt to restore the pointers - each value is de-serialized into a new
83/// Rc<RefCell<T>> with a reference count of one.
84///
85/// The shared references can be reconstructed using the ids stored, as before serialization these
86/// were unique for each separate instance of `T` in memory. See [`RcRefCellAsId`].
87pub struct RcRefCellAsInner;
88
89impl<T> SerializeAs<Rc<RefCell<T>>> for RcRefCellAsInner
90where
91    T: Serialize + HasId,
92{
93    fn serialize_as<S>(source: &Rc<RefCell<T>>, serializer: S) -> Result<S::Ok, S::Error>
94    where
95        S: serde::Serializer,
96    {
97        (**source).borrow().serialize(serializer)
98    }
99}
100
101impl<T> SerializeAs<Rc<T>> for RcRefCellAsInner
102where
103    T: Serialize + HasId,
104{
105    fn serialize_as<S>(source: &Rc<T>, serializer: S) -> Result<S::Ok, S::Error>
106    where
107        S: serde::Serializer,
108    {
109        source.serialize(serializer)
110    }
111}
112
113impl<'de, T> DeserializeAs<'de, Rc<RefCell<T>>> for RcRefCellAsInner
114where
115    T: Deserialize<'de> + HasId + DefaultWithId,
116{
117    fn deserialize_as<D>(deserializer: D) -> Result<Rc<RefCell<T>>, D::Error>
118    where
119        D: serde::Deserializer<'de>,
120    {
121        let val = T::deserialize(deserializer)?;
122        Ok(Rc::new(RefCell::new(val)))
123    }
124}
125
126impl<'de, T> DeserializeAs<'de, Rc<T>> for RcRefCellAsInner
127where
128    T: Deserialize<'de> + HasId + DefaultWithId,
129{
130    fn deserialize_as<D>(deserializer: D) -> Result<Rc<T>, D::Error>
131    where
132        D: serde::Deserializer<'de>,
133    {
134        let val = T::deserialize(deserializer)?;
135        Ok(Rc::new(val))
136    }
137}