Skip to main content

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