Skip to main content

harmos_storage/
schema_encoding.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12/* === Re-Exports === */
13
14/* === Imports === */
15
16// Standard Library Imports
17
18// Third Party Imports
19use serde::de::{DeserializeSeed, Error as _, IntoDeserializer, MapAccess, Visitor};
20use serde::ser::SerializeStruct;
21use serde::{Deserialize, Deserializer, Serialize, Serializer};
22// Local Imports
23use super::manager::encoded_size;
24use super::{SchemaKey, StorageCursor, StorageSchema};
25use crate::{Error, Result};
26
27/* === Constants === */
28
29/* === Macros === */
30
31/* === Type Aliases === */
32
33/* === Structs === */
34
35struct Input<A> {
36    map: A,
37    position: Option<StorageCursor>,
38    key: Option<SchemaKey>,
39    encoding: Option<Encoding>,
40}
41
42struct StorageVisitor;
43
44/* === Enums === */
45
46#[derive(Deserialize)]
47#[serde(rename_all = "snake_case")]
48enum Encoding {
49    GraphV1,
50}
51
52/* === Traits === */
53
54/* === Implementations === */
55
56impl StorageSchema {
57    pub(super) fn encoded_bytes(&self) -> Result<usize> {
58        self.schema.preparation(&harmos_domain::config::SchemaSettings::default()).map_err(|_| invalid())?;
59        encoded_size(self)
60    }
61}
62
63impl Serialize for StorageSchema {
64    fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
65        let mut output = serializer.serialize_struct("StorageSchema", 5)?;
66        output.serialize_field("position", &self.position)?;
67        output.serialize_field("key", &self.key)?;
68        output.serialize_field("encoding", "graph_v1")?;
69        output.serialize_field("root", &self.schema.root)?;
70        output.serialize_field("definitions", &self.schema.definitions)?;
71        output.end()
72    }
73}
74
75impl<'de> Deserialize<'de> for StorageSchema {
76    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
77        deserializer.deserialize_map(StorageVisitor).map_err(|error| D::Error::custom(format!(
78            "invalid graph_v1 storage schema: {error}; inline metadata is unsupported; retain the original data and select a fresh storage root",
79        )))
80    }
81}
82
83impl<'de> Visitor<'de> for StorageVisitor {
84    type Value = StorageSchema;
85    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
86        formatter.write_str("bounded graph_v1 storage metadata")
87    }
88    fn visit_map<A: MapAccess<'de>>(self, map: A) -> std::result::Result<Self::Value, A::Error> {
89        let mut input = Input {
90            map,
91            position: None,
92            key: None,
93            encoding: None,
94        };
95        // Forward Only The Graph Fields To The Canonical Seed Without Buffering
96        // The JSON Object Or Allocating A Second Representation Of Its Fields.
97        let schema = crate::schema::graph::Seed {
98            settings: &harmos_domain::config::SchemaSettings::default(),
99        }
100        .deserialize(serde::de::value::MapAccessDeserializer::new(&mut input))?;
101        let Encoding::GraphV1 = input.encoding.ok_or_else(|| A::Error::missing_field("encoding"))?;
102        Ok(StorageSchema::new(
103            input.position.ok_or_else(|| A::Error::missing_field("position"))?,
104            input.key.ok_or_else(|| A::Error::missing_field("key"))?,
105            schema,
106        ))
107    }
108}
109
110impl<'de, A: MapAccess<'de>> MapAccess<'de> for Input<A> {
111    type Error = A::Error;
112    fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> std::result::Result<Option<K::Value>, A::Error> {
113        while let Some(key) = self.map.next_key::<String>()? {
114            match key.as_str() {
115                "position" => {
116                    if self.position.is_some() {
117                        return Err(A::Error::duplicate_field("position"));
118                    }
119                    self.position = Some(self.map.next_value()?);
120                }
121                "key" => {
122                    if self.key.is_some() {
123                        return Err(A::Error::duplicate_field("key"));
124                    }
125                    self.key = Some(self.map.next_value()?);
126                }
127                "encoding" => {
128                    if self.encoding.is_some() {
129                        return Err(A::Error::duplicate_field("encoding"));
130                    }
131                    self.encoding = Some(self.map.next_value()?);
132                }
133                _ => return seed.deserialize(key.into_deserializer()).map(Some),
134            }
135        }
136        Ok(None)
137    }
138    fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> std::result::Result<V::Value, A::Error> {
139        self.map.next_value_seed(seed)
140    }
141}
142
143/* === Public Functions === */
144
145/* === Private Functions === */
146
147fn invalid() -> Error {
148    Error::InvalidInput {
149        field: "storage schema",
150        reason: "invalid shared schema preparation",
151    }
152}
153
154/* === Tests === */