sylt_common/
flat_value.rs

1use serde::{Deserialize, Serialize};
2use std::cell::RefCell;
3use std::collections::{HashMap, HashSet, hash_map::Entry};
4use std::rc::Rc;
5
6use crate::{Type, UpValue, Value};
7
8/// The serialized version of a pointer.
9pub type FlatValueID = usize;
10
11/// A value packed with pointers replaced with [FlatValueID],
12/// which point into an accompanying vector.
13#[derive(Clone, Debug, Deserialize, Serialize)]
14pub enum FlatValue {
15    Field(String),
16    Ty(Type),
17    Blob(usize),
18    Instance(usize, HashMap<String, FlatValueID>),
19    Tuple(Vec<FlatValueID>),
20    List(Vec<FlatValueID>),
21    Set(HashSet<FlatValueID>),
22    Dict(HashMap<FlatValueID, FlatValueID>),
23    Float(f64),
24    Int(i64),
25    Bool(bool),
26    String(String),
27    Function(Vec<FlatUpValue>, Type, usize),
28    ExternFunction(usize),
29    Unknown,
30    Nil,
31}
32
33/// One [Value] packed up and ready to be serialized.
34pub type FlatValuePack = Vec<FlatValue>;
35
36impl FlatValue {
37    /// Makes a value serializable
38    ///
39    /// Since values might have loops - nothing is garanteed about the ordering except that 0 is
40    /// the original value being packed.
41    pub fn pack(value: &Value) -> FlatValuePack {
42        let mut pack = Vec::new();
43        let mut seen = HashMap::new();
44        Self::pack_inner(value, &mut pack, &mut seen);
45        pack
46    }
47
48    /// Helper function to package values recursively into a 'flat' [Vec].
49    fn pack_inner(value: &Value, pack: &mut FlatValuePack, seen: &mut HashMap<usize, FlatValueID>) -> FlatValueID {
50        let id = pack.len();
51        match seen.entry(value.unique_id()) {
52            Entry::Occupied(entry) => { return *entry.get(); }
53            Entry::Vacant(entry) => { entry.insert(id); }
54        }
55        pack.push(FlatValue::Nil);
56
57        let val = match value {
58            Value::Field(s) => FlatValue::Field(s.into()),
59            Value::Ty(ty) => FlatValue::Ty(ty.clone()),
60            Value::Blob(slot) => FlatValue::Blob(*slot),
61            Value::Instance(ty_slot, values) => FlatValue::Instance(
62                *ty_slot,
63                values
64                    .borrow()
65                    .iter()
66                    .map(|(field, value)| (field.clone(), Self::pack_inner(value, pack, seen)))
67                    .collect(),
68            ),
69            Value::Tuple(values) => FlatValue::Tuple(
70                values.iter().map(|value| Self::pack_inner(value, pack, seen)).collect(),
71            ),
72            Value::List(values) => FlatValue::List(
73                values.borrow().iter().map(|value| Self::pack_inner(value, pack, seen)).collect(),
74            ),
75            Value::Set(values) => FlatValue::Set(
76                values.borrow().iter().map(|value| Self::pack_inner(value, pack, seen)).collect(),
77            ),
78            Value::Dict(values) => FlatValue::Dict(
79                values
80                    .borrow()
81                    .iter()
82                    .map(|(v1, v2)| (Self::pack_inner(v1, pack, seen), Self::pack_inner(v2, pack, seen)))
83                    .collect(),
84            ),
85            Value::Float(f) => FlatValue::Float(*f),
86            Value::Int(i) => FlatValue::Int(*i),
87            Value::Bool(b) => FlatValue::Bool(*b),
88            Value::String(s) => FlatValue::String(String::clone(s)),
89            Value::Function(captured, ty, slot) => FlatValue::Function(
90                captured
91                    .iter()
92                    .map(|upvalue| FlatUpValue { slot: upvalue.borrow().slot, value: Self::pack_inner(&upvalue.borrow().value, pack, seen) })
93                    .collect(),
94                ty.clone(),
95                *slot,
96            ),
97            Value::ExternFunction(slot) => FlatValue::ExternFunction(*slot),
98            Value::Unknown => FlatValue::Unknown,
99            Value::Nil => FlatValue::Nil,
100            Value::Union(_) => {
101                unreachable!("Cannot send union values over the network");
102            }
103        };
104        pack[id] = val;
105        id
106    }
107
108    /// Unpacks one value without going deeper. Only the top-level value is unpacked, and all
109    /// sub types are filled with placeholders.
110    fn partial_unpack(value: FlatValue) -> Value {
111        match value {
112            FlatValue::Field(s) => Value::Field(s),
113            FlatValue::Ty(ty) => Value::Ty(ty),
114            FlatValue::Blob(slot) => Value::Blob(slot),
115            FlatValue::Instance(ty_slot, _) => Value::Instance(
116                ty_slot,
117                Rc::new(RefCell::new(HashMap::new())),
118            ),
119            // Tuple is specificly tricky - since it doesn't have a RefCell.
120            FlatValue::Tuple(_) => Value::Tuple(Rc::new(Vec::new())),
121            FlatValue::List(_) => Value::List(Rc::new(RefCell::new(Vec::new()))),
122            FlatValue::Set(_) => Value::Set(Rc::new(RefCell::new(HashSet::new()))),
123            FlatValue::Dict(_) => Value::Dict(Rc::new(RefCell::new(HashMap::new()))),
124            FlatValue::Float(f) => Value::Float(f),
125            FlatValue::Int(i) => Value::Int(i),
126            FlatValue::Bool(b) => Value::Bool(b),
127            FlatValue::String(s) => Value::String(Rc::new(s)),
128            // Function is specificly tricky - since it doesn't have a RefCell.
129            FlatValue::Function(_, ty, slot) => Value::Function(
130                Rc::new(Vec::new()),
131                ty,
132                slot,
133            ),
134            FlatValue::ExternFunction(slot) => Value::ExternFunction(slot),
135            FlatValue::Unknown => Value::Unknown,
136            FlatValue::Nil => Value::Nil,
137        }
138    }
139
140    /// Reconstructs the packaged  Value - with correct references.
141    ///
142    /// Keep in mind that values will be cloned here.
143    pub fn unpack(pack: &FlatValuePack) -> Value {
144        // The first unpacking removes all order requirements,
145        // but it does force us to use a bit of unsafe rust-code.
146        let mut mapping: Vec<Value> = pack.iter().cloned().map(Self::partial_unpack).collect();
147        for (i, x) in mapping.iter().enumerate() {
148            match (&pack[i], x) {
149                (FlatValue::Tuple(flat), Value::Tuple(values)) => {
150                    // We know the Rc hasn't moved out of this function - but we cannot
151                    // garantee the requirements for `get_mut()` here. The container never moves
152                    // so it is safe - this is a very precise piece of code.
153                    let values = unsafe { (Rc::as_ptr(values) as *mut Vec<Value>).as_mut() }.unwrap();
154                    for id in flat {
155                        values.push(mapping[*id].clone());
156                    }
157                }
158                (FlatValue::Function(flat, _, _), Value::Function(values, _, _)) => {
159                    // See the tuple comment
160                    let values = unsafe { (Rc::as_ptr(values) as *mut Vec<Rc<RefCell<UpValue>>>).as_mut() }.unwrap();
161                    for up in flat {
162                        values.push(Rc::new(RefCell::new(UpValue { slot: up.slot, value: mapping[up.value].clone() })));
163                    }
164                }
165                (FlatValue::Instance(_, flat), Value::Instance(_, values)) => {
166                    let mut values = values.borrow_mut();
167                    for (key, id) in flat {
168                        values.insert(key.clone(), mapping[*id].clone());
169                    }
170                }
171                (FlatValue::List(flat), Value::List(values)) => {
172                    let mut values = values.borrow_mut();
173                    for id in flat {
174                        values.push(mapping[*id].clone());
175                    }
176                }
177                (FlatValue::Set(flat), Value::Set(values)) => {
178                    let mut values = values.borrow_mut();
179                    for id in flat {
180                        values.insert(mapping[*id].clone());
181                    }
182                }
183                (FlatValue::Dict(flat), Value::Dict(values)) => {
184                    let mut values = values.borrow_mut();
185                    for (key_id, value_id) in flat {
186                        values.insert(mapping[*key_id].clone(), mapping[*value_id].clone());
187                    }
188                }
189                _ => {}
190            }
191        }
192
193        mapping.remove(0)
194    }
195}
196
197/// Corresponds to a [UpValue] - but with a serializable id instead of a reference.
198#[derive(Clone, Debug, Deserialize, Serialize)]
199pub struct FlatUpValue {
200    slot: usize,
201    value: FlatValueID,
202}
203