Skip to main content

lashlang/runtime/
state.rs

1use std::sync::Arc;
2
3use super::{
4    ProjectedValue, Record, SnapshotJson, Value, image_from_json_map, record_with_capacity,
5    resource_from_json_map,
6};
7use serde::ser::SerializeStruct;
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10const PROJECTED_SNAPSHOT_TAG: &str = "__lashlang_snapshot_projected__";
11const PROJECTED_SNAPSHOT_NAME: &str = "name";
12const PROJECTED_SNAPSHOT_TYPE_NAME: &str = "type_name";
13const PROJECTED_SNAPSHOT_PROJECTION_REF: &str = "projection_ref";
14const TUPLE_SNAPSHOT_TAG: &str = "__lashlang_snapshot_tuple__";
15const TUPLE_SNAPSHOT_ITEMS: &str = "items";
16
17#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
18pub struct State {
19    pub(super) globals: Record,
20}
21
22impl State {
23    pub fn new() -> Self {
24        Self::default()
25    }
26
27    pub fn globals(&self) -> &Record {
28        &self.globals
29    }
30
31    pub fn snapshot(&self) -> Snapshot {
32        Snapshot {
33            globals: self.globals.clone(),
34        }
35    }
36
37    pub fn from_snapshot(snapshot: Snapshot) -> Self {
38        Self {
39            globals: snapshot.globals,
40        }
41    }
42}
43
44#[derive(Clone, Debug, Default, PartialEq)]
45pub struct Snapshot {
46    pub globals: Record,
47}
48
49impl Serialize for Snapshot {
50    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
51    where
52        S: Serializer,
53    {
54        let mut state = serializer.serialize_struct("Snapshot", 1)?;
55        state.serialize_field(
56            "globals",
57            &SnapshotJson(&Value::Record(Arc::new(self.globals.clone()))),
58        )?;
59        state.end()
60    }
61}
62
63impl<'de> Deserialize<'de> for Snapshot {
64    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
65    where
66        D: Deserializer<'de>,
67    {
68        #[derive(Deserialize)]
69        struct SnapshotWire {
70            globals: serde_json::Map<String, serde_json::Value>,
71        }
72
73        let wire = SnapshotWire::deserialize(deserializer)?;
74        Ok(Self {
75            globals: snapshot_record_from_json(wire.globals),
76        })
77    }
78}
79
80fn snapshot_record_from_json(map: serde_json::Map<String, serde_json::Value>) -> Record {
81    let mut record = record_with_capacity(map.len());
82    for (key, value) in map {
83        record.insert(key, snapshot_value_from_json(value));
84    }
85    record
86}
87
88fn snapshot_value_from_json(value: serde_json::Value) -> Value {
89    match value {
90        serde_json::Value::Null => Value::Null,
91        serde_json::Value::Bool(value) => Value::Bool(value),
92        serde_json::Value::Number(value) => Value::Number(value.as_f64().unwrap_or_default()),
93        serde_json::Value::String(value) => Value::String(value.into()),
94        serde_json::Value::Array(values) => Value::List(
95            values
96                .into_iter()
97                .map(snapshot_value_from_json)
98                .collect::<Vec<_>>()
99                .into(),
100        ),
101        serde_json::Value::Object(map) => {
102            if let Some(items) = tuple_snapshot_marker(&map) {
103                return Value::Tuple(
104                    items
105                        .into_iter()
106                        .map(snapshot_value_from_json)
107                        .collect::<Vec<_>>()
108                        .into(),
109                );
110            }
111            if let Some((name, type_name, projection_ref)) = projected_snapshot_marker(&map) {
112                return Value::Projected(
113                    ProjectedValue::unavailable_after_restore_with_projection_ref(
114                        name,
115                        type_name,
116                        projection_ref,
117                    ),
118                );
119            }
120            image_from_json_map(&map)
121                .map(Value::Image)
122                .or_else(|| resource_from_json_map(&map).map(Value::Resource))
123                .unwrap_or_else(|| Value::Record(Arc::new(snapshot_record_from_json(map))))
124        }
125    }
126}
127
128fn tuple_snapshot_marker(
129    map: &serde_json::Map<String, serde_json::Value>,
130) -> Option<Vec<serde_json::Value>> {
131    if map.len() != 2 {
132        return None;
133    }
134    if !map.get(TUPLE_SNAPSHOT_TAG)?.as_bool()? {
135        return None;
136    }
137    let serde_json::Value::Array(items) = map.get(TUPLE_SNAPSHOT_ITEMS)?.clone() else {
138        return None;
139    };
140    Some(items)
141}
142
143fn projected_snapshot_marker(
144    map: &serde_json::Map<String, serde_json::Value>,
145) -> Option<(String, String, Option<serde_json::Value>)> {
146    if map.len() != 3 && map.len() != 4 {
147        return None;
148    }
149    if !map.get(PROJECTED_SNAPSHOT_TAG)?.as_bool()? {
150        return None;
151    }
152    let name = map.get(PROJECTED_SNAPSHOT_NAME)?.as_str()?.to_string();
153    let type_name = map.get(PROJECTED_SNAPSHOT_TYPE_NAME)?.as_str()?.to_string();
154    let projection_ref = map.get(PROJECTED_SNAPSHOT_PROJECTION_REF).cloned();
155    Some((name, type_name, projection_ref))
156}