oca_ast_transformation/ast/
mod.rs

1use indexmap::IndexMap;
2use serde::{
3    de::{self, MapAccess, Visitor},
4    ser::SerializeStruct,
5    Deserialize, Deserializer, Serialize, Serializer,
6};
7use std::hash::Hash;
8use std::{collections::HashMap, fmt};
9
10pub mod error;
11
12#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
13pub struct TransformationAST {
14    pub version: String,
15    pub commands: Vec<Command>,
16    pub commands_meta: IndexMap<usize, CommandMeta>,
17    pub meta: HashMap<String, String>,
18}
19
20#[derive(Debug, PartialEq, Serialize, Clone)]
21pub struct Command {
22    #[serde(rename = "type")]
23    pub kind: CommandType,
24    #[serde(flatten)]
25    pub object_kind: ObjectKind,
26}
27
28#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
29pub struct CommandMeta {
30    pub line_number: usize,
31    pub raw_line: String,
32}
33
34#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
35pub enum CommandType {
36    Rename,
37    Link,
38}
39
40#[derive(Debug, PartialEq, Clone, Eq)]
41pub enum ObjectKind {
42    // Transformation(TransformationType),
43    Rename(RenameContent),
44    Link(LinkContent),
45}
46
47#[derive(Debug, PartialEq, Clone, Eq)]
48pub enum TransformationType {
49    Rename(RenameContent),
50    Link(LinkContent),
51}
52
53#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq)]
54pub struct RenameContent {
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub attributes: Option<IndexMap<String, String>>,
57}
58
59#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq)]
60pub struct LinkContent {
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub attributes: Option<IndexMap<String, String>>,
63}
64
65impl Hash for ObjectKind {
66    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
67        match self {
68            ObjectKind::Rename(content) => {
69                content.hash(state);
70            }
71            ObjectKind::Link(content) => {
72                content.hash(state);
73            }
74        }
75    }
76}
77
78impl Hash for RenameContent {
79    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
80        if let Some(attributes) = &self.attributes {
81            for (key, value) in attributes {
82                key.hash(state);
83                value.hash(state);
84            }
85        }
86    }
87}
88
89impl Hash for LinkContent {
90    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
91        if let Some(attributes) = &self.attributes {
92            for (key, value) in attributes {
93                key.hash(state);
94                value.hash(state);
95            }
96        }
97    }
98}
99
100/* impl ObjectKind {
101    pub fn capture_content(&self) -> Option<&CaptureContent> {
102        match self {
103            ObjectKind::CaptureBase(content) => Some(content),
104            _ => None,
105        }
106    }
107
108    pub fn overlay_content(&self) -> Option<&Content> {
109        match self {
110            ObjectKind::Overlay(_, content) => Some(content),
111            _ => None,
112        }
113    }
114    pub fn oca_bundle_content(&self) -> Option<&BundleContent> {
115        match self {
116            ObjectKind::OCABundle(content) => Some(content),
117            _ => None,
118        }
119    }
120} */
121
122impl Serialize for ObjectKind {
123    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
124    where
125        S: Serializer,
126    {
127        let mut state = serializer.serialize_struct("ObjectKind", 3)?;
128        match self {
129            ObjectKind::Rename(content) => {
130                state.serialize_field("object_kind", "Rename")?;
131                state.serialize_field("content", content)?;
132            }
133            ObjectKind::Link(content) => {
134                state.serialize_field("object_kind", "Link")?;
135                state.serialize_field("content", content)?;
136            }
137        }
138        state.end()
139    }
140}
141
142#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq)]
143#[serde(untagged)]
144pub enum NestedValue {
145    Value(String),
146    Object(IndexMap<String, NestedValue>),
147    Array(Vec<NestedValue>),
148}
149impl NestedValue {
150    /* fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
151        match self {
152            NestedValue::Value(value) => {
153                value.hash(state);
154            }
155            NestedValue::Object(object) => {
156                for (key, value) in object {
157                    key.hash(state);
158                    value.hash(state);
159                }
160            }
161            NestedValue::Array(array) => {
162                for value in array {
163                    value.hash(state);
164                }
165            }
166        }
167    } */
168}
169// Implement Deserialize for Command
170impl<'de> Deserialize<'de> for Command {
171    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
172    where
173        D: Deserializer<'de>,
174    {
175        enum Field {
176            Kind,
177            ObjectKind,
178        }
179
180        impl<'de> Deserialize<'de> for Field {
181            fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
182            where
183                D: Deserializer<'de>,
184            {
185                struct FieldVisitor;
186
187                impl Visitor<'_> for FieldVisitor {
188                    type Value = Field;
189
190                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
191                        formatter.write_str("`type` or `object_kind`")
192                    }
193
194                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
195                    where
196                        E: de::Error,
197                    {
198                        match value {
199                            "type" => Ok(Field::Kind),
200                            "object_kind" => Ok(Field::ObjectKind),
201                            _ => Err(de::Error::unknown_field(value, FIELDS)),
202                        }
203                    }
204                }
205
206                deserializer.deserialize_identifier(FieldVisitor)
207            }
208        }
209
210        struct CommandVisitor;
211
212        impl<'de> Visitor<'de> for CommandVisitor {
213            type Value = Command;
214
215            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
216                formatter.write_str("struct Command")
217            }
218
219            fn visit_map<V>(self, mut map: V) -> Result<Command, V::Error>
220            where
221                V: MapAccess<'de>,
222            {
223                let mut kind = None;
224                let mut object_kind = None;
225
226                while let Some(key) = map.next_key()? {
227                    match key {
228                        Field::Kind => {
229                            if kind.is_some() {
230                                return Err(de::Error::duplicate_field("type"));
231                            }
232                            kind = Some(map.next_value()?);
233                        }
234                        Field::ObjectKind => {
235                            if object_kind.is_some() {
236                                return Err(de::Error::duplicate_field("object_kind"));
237                            }
238                            let object_kind_str: String = map.next_value()?;
239                            match object_kind_str.as_str() {
240                                "Rename" => {
241                                    // take the key frist otherwise next value would not work
242                                    // properly
243                                    let _content_key: Option<String> = map.next_key()?;
244                                    let content: RenameContent = map.next_value()?;
245                                    object_kind = Some(ObjectKind::Rename(content));
246                                }
247                                "Link" => {
248                                    // take the key frist otherwise next value would not work
249                                    // properly
250                                    let _content_key: Option<String> = map.next_key()?;
251                                    let content: LinkContent = map.next_value()?;
252                                    object_kind = Some(ObjectKind::Link(content));
253                                }
254                                _ => {}
255                            }
256                        }
257                    }
258                }
259
260                let kind = kind.ok_or_else(|| de::Error::missing_field("type"))?;
261                let object_kind =
262                    object_kind.ok_or_else(|| de::Error::missing_field("object_kind"))?;
263
264                Ok(Command { kind, object_kind })
265            }
266        }
267
268        const FIELDS: &[&str] = &["type", "object_kind", "content"];
269        const _VARIANTS: &[&str] = &["Rename"];
270        deserializer.deserialize_struct("Command", FIELDS, CommandVisitor)
271    }
272}
273
274impl TransformationAST {
275    pub fn new() -> Self {
276        TransformationAST {
277            // Version of OCA specification
278            version: String::from("1.0.0"),
279            commands: Vec::new(),
280            commands_meta: IndexMap::new(),
281            meta: HashMap::new(),
282        }
283    }
284}
285
286impl Default for TransformationAST {
287    fn default() -> Self {
288        Self::new()
289    }
290}
291
292/*
293impl Serialize for ObjectKind {
294    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
295    where
296        S: Serializer,
297    {
298        match self {
299            ObjectKind::CaptureBase => serializer.serialize_str("CaptureBase"),
300            ObjectKind::OCABundle => serializer.serialize_str("OCABundle"),
301            ObjectKind::Overlay(overlay_type) => {
302                serializer.serialize_str(overlay_type.to_string().as_str())
303            }
304        }
305    }
306}*/
307
308impl From<u8> for ObjectKind {
309    fn from(val: u8) -> Self {
310        match val {
311            0 => ObjectKind::Rename(RenameContent { attributes: None }),
312            1 => ObjectKind::Link(LinkContent { attributes: None }),
313            _ => panic!("Unknown object type"),
314        }
315    }
316}
317
318impl From<ObjectKind> for u8 {
319    fn from(val: ObjectKind) -> Self {
320        match val {
321            ObjectKind::Rename(_) => 0,
322            ObjectKind::Link(_) => 1,
323        }
324    }
325}
326
327impl<'de> Deserialize<'de> for ObjectKind {
328    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
329    where
330        D: Deserializer<'de>,
331    {
332        let s = String::deserialize(deserializer)?;
333        match s.as_str() {
334            "Rename" => Ok(ObjectKind::Rename(RenameContent { attributes: None })),
335            "Link" => Ok(ObjectKind::Link(LinkContent { attributes: None })),
336            _ => Err(serde::de::Error::custom(format!(
337                "unknown object kind: {}",
338                s
339            ))),
340        }
341    }
342}
343
344#[cfg(test)]
345mod tests {
346    use super::*;
347
348    #[test]
349    fn test_ast_serialize() {
350        let mut attributes = IndexMap::new();
351
352        attributes.insert("digest".to_string(), "d".to_string());
353        let command = Command {
354            kind: CommandType::Rename,
355            object_kind: ObjectKind::Rename(RenameContent {
356                attributes: Some(attributes),
357            }),
358        };
359
360        let mut ast = TransformationAST::new();
361        ast.commands.push(command);
362
363        let serialized = serde_json::to_string(&ast).unwrap();
364        assert_eq!(
365            serialized,
366            r#"{"version":"1.0.0","commands":[{"type":"Rename","object_kind":"Rename","content":{"attributes":{"digest":"d"}}}],"commands_meta":{},"meta":{}}"#
367        );
368
369        let deser: TransformationAST = serde_json::from_str(&serialized).unwrap();
370        assert_eq!(ast, deser);
371    }
372}