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 serde::{Deserialize, Deserializer, Serialize, Serializer};
7use serde_with::{DeserializeAs, SerializeAs};
8use std::fmt::Display;
9use ustr::Ustr;
10
11/// A unique id, used to distinguish between objects of the same type.
12///
13///
14/// This is used for pointer translation during (de)serialisation.
15#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize, Hash)]
16pub struct ObjId {
17 /// a unique identifier of the type of this object
18 pub type_name: Ustr,
19
20 /// unique between objects of the same type
21 pub object_id: u32,
22}
23
24impl Display for ObjId {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 write!(f, "obj_id_{}_{}", self.type_name, self.object_id)
27 }
28}
29
30/// A type with an [`ObjectId`].
31///
32/// Implementing types should ensure that the id is updated when an object is cloned.
33pub trait HasId {
34 const TYPE_NAME: &'static str;
35
36 /// The id of this object.
37 fn id(&self) -> ObjId;
38}
39
40/// A type that can be created with default values and an id.
41pub trait DefaultWithId: HasId {
42 /// Creates a new default value of type `T`, but with the given id.
43 fn default_with_id(id: ObjId) -> Self;
44}
45
46/// A "fat pointer" to some shared data with an ID, such as [DeclarationPtr] or [SymbolTablePtr].
47///
48/// These are usually an [Arc] containing
49/// - A unique, immutable ID
50/// - A shared container for the data, such as an [RwLock]
51///
52/// Implementing this trait makes it possible to serialise the **contents** of such pointers
53/// with [PtrAsInner]; See its docstring for more information.
54pub(super) trait IdPtr: HasId + DefaultWithId {
55 type Data: Serialize + for<'de> Deserialize<'de>;
56
57 /// Get a copy of the underlying data
58 fn get_data(&self) -> Self::Data;
59
60 /// Re-construct the pointer given the ID and inner data
61 fn with_id_and_data(id: ObjId, data: Self::Data) -> Self;
62}
63
64/// Serialises the object's ID. The actual data is **NOT stored**.
65///
66/// # WARNING
67///
68/// The object is de-serialised with the correct ID, but an empty default value.
69///
70/// After de-serialising an entire structure, it is **the user's responsibility**
71/// to find a complete copy of the object and restore the shared pointer to it.
72/// This should be possible as long as at least one instance of the object has
73/// been serialised with [PtrAsInner].
74///
75/// See the de-serialisation code for [Model] for an example.
76///
77pub struct AsId;
78
79impl<T> SerializeAs<T> for AsId
80where
81 T: HasId,
82{
83 fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
84 where
85 S: Serializer,
86 {
87 source.id().serialize(serializer)
88 }
89}
90
91impl<'de, T> DeserializeAs<'de, T> for AsId
92where
93 T: HasId + DefaultWithId,
94{
95 fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
96 where
97 D: Deserializer<'de>,
98 {
99 let id = ObjId::deserialize(deserializer)?;
100 Ok(T::default_with_id(id))
101 }
102}
103
104/// Serialises a shared pointer to some object `x` as a tuple `(ID, X)`, where:
105/// - `ID` is the unique and immutable ID of the object. (See: [HasId])
106/// - `X` is a full copy of the object's value.
107/// (See `x`'s implementation of the [Serialize] trait for details)
108///
109/// On de-serialisation, **independent copies** of the object with the same ID are created.
110///
111/// # WARNING
112///
113/// De-serialisation makes **no attempt** to restore shared pointers.
114/// Two pointers to the same value `x` will be de-serialised as **two separate copies**
115/// of it, `x'` and `x''`. Mutating the value of `x'` will **not** change the value of `x''`.
116///
117/// After de-serialising an entire structure, it is the user's responsibility to go through it
118/// and manually restore the shared pointers. See the de-serialisation code for [Model]
119/// for an example.
120pub struct PtrAsInner;
121
122#[derive(Serialize, Deserialize)]
123struct PtrAsInnerStored<T> {
124 id: ObjId,
125 #[serde(flatten)]
126 data: T,
127}
128
129impl<T> SerializeAs<T> for PtrAsInner
130where
131 T: IdPtr,
132{
133 fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
134 where
135 S: Serializer,
136 {
137 let stored = PtrAsInnerStored {
138 id: source.id(),
139 data: source.get_data(),
140 };
141 stored.serialize(serializer)
142 }
143}
144
145impl<'de, T> DeserializeAs<'de, T> for PtrAsInner
146where
147 T: IdPtr,
148 T::Data: Deserialize<'de>,
149{
150 fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
151 where
152 D: Deserializer<'de>,
153 {
154 let stored = PtrAsInnerStored::deserialize(deserializer)?;
155 Ok(T::with_id_and_data(stored.id, stored.data))
156 }
157}