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

            
6
use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
use serde_with::{DeserializeAs, SerializeAs};
8
use std::fmt::Display;
9
use 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)]
16
pub 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

            
24
impl 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.
33
pub 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.
41
pub 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.
54
pub(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
///
77
pub struct AsId;
78

            
79
impl<T> SerializeAs<T> for AsId
80
where
81
    T: HasId,
82
{
83
422
    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
84
422
    where
85
422
        S: Serializer,
86
    {
87
422
        source.id().serialize(serializer)
88
422
    }
89
}
90

            
91
impl<'de, T> DeserializeAs<'de, T> for AsId
92
where
93
    T: HasId + DefaultWithId,
94
{
95
168
    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
96
168
    where
97
168
        D: Deserializer<'de>,
98
    {
99
168
        let id = ObjId::deserialize(deserializer)?;
100
168
        Ok(T::default_with_id(id))
101
168
    }
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.
120
pub struct PtrAsInner;
121

            
122
#[derive(Serialize, Deserialize)]
123
struct PtrAsInnerStored<T> {
124
    id: ObjId,
125
    #[serde(flatten)]
126
    data: T,
127
}
128

            
129
impl<T> SerializeAs<T> for PtrAsInner
130
where
131
    T: IdPtr,
132
{
133
1344
    fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
134
1344
    where
135
1344
        S: Serializer,
136
    {
137
1344
        let stored = PtrAsInnerStored {
138
1344
            id: source.id(),
139
1344
            data: source.get_data(),
140
1344
        };
141
1344
        stored.serialize(serializer)
142
1344
    }
143
}
144

            
145
impl<'de, T> DeserializeAs<'de, T> for PtrAsInner
146
where
147
    T: IdPtr,
148
    T::Data: Deserialize<'de>,
149
{
150
536
    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
151
536
    where
152
536
        D: Deserializer<'de>,
153
    {
154
536
        let stored = PtrAsInnerStored::deserialize(deserializer)?;
155
536
        Ok(T::with_id_and_data(stored.id, stored.data))
156
536
    }
157
}