oca_ast/ast/
mod.rs

1use indexmap::IndexMap;
2use said::SelfAddressingIdentifier;
3use serde::{
4    de::{self, MapAccess, Visitor},
5    ser::SerializeStruct,
6    Deserialize, Deserializer, Serialize, Serializer,
7};
8use std::hash::Hash;
9use std::{collections::HashMap, fmt, str::FromStr};
10use strum_macros::Display;
11use thiserror::Error;
12use wasm_bindgen::prelude::*;
13
14pub use self::attributes::NestedAttrType;
15
16pub mod attributes;
17pub mod error;
18pub mod recursive_attributes;
19
20#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
21pub struct OCAAst {
22    pub version: String,
23    pub commands: Vec<Command>,
24    pub commands_meta: IndexMap<usize, CommandMeta>,
25    pub meta: HashMap<String, String>,
26}
27
28#[derive(Debug, PartialEq, Serialize, Clone)]
29pub struct Command {
30    #[serde(rename = "type")]
31    pub kind: CommandType,
32    #[serde(flatten)]
33    pub object_kind: ObjectKind,
34}
35
36#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
37pub struct CommandMeta {
38    pub line_number: usize,
39    pub raw_line: String,
40}
41
42#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
43pub enum CommandType {
44    Add,
45    Remove,
46    Modify,
47    From,
48}
49
50#[derive(Debug, PartialEq, Clone, Eq)]
51pub enum ObjectKind {
52    CaptureBase(CaptureContent),
53    OCABundle(BundleContent),
54    Overlay(OverlayType, Content),
55}
56
57impl Hash for ObjectKind {
58    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
59        match self {
60            ObjectKind::CaptureBase(content) => {
61                content.hash(state);
62            }
63            ObjectKind::OCABundle(content) => {
64                content.hash(state);
65            }
66            // TODO hash over content as well?
67            ObjectKind::Overlay(overlay_type, _) => {
68                overlay_type.hash(state);
69            }
70        }
71    }
72}
73
74impl Hash for CaptureContent {
75    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
76        match &self.attributes {
77            Some(attributes) => {
78                for (key, value) in attributes {
79                    key.hash(state);
80                    value.hash(state);
81                }
82            }
83            None => {}
84        }
85        match &self.properties {
86            Some(properties) => {
87                for (key, value) in properties {
88                    key.hash(state);
89                    value.hash(state);
90                }
91            }
92            None => {}
93        }
94    }
95}
96
97impl ObjectKind {
98    pub fn capture_content(&self) -> Option<&CaptureContent> {
99        match self {
100            ObjectKind::CaptureBase(content) => Some(content),
101            _ => None,
102        }
103    }
104
105    pub fn overlay_content(&self) -> Option<&Content> {
106        match self {
107            ObjectKind::Overlay(_, content) => Some(content),
108            _ => None,
109        }
110    }
111    pub fn oca_bundle_content(&self) -> Option<&BundleContent> {
112        match self {
113            ObjectKind::OCABundle(content) => Some(content),
114            _ => None,
115        }
116    }
117}
118#[wasm_bindgen]
119#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy, Display, Eq, Hash)]
120pub enum AttributeType {
121    Boolean,
122    Binary,
123    Text,
124    Numeric,
125    DateTime,
126}
127
128impl FromStr for AttributeType {
129    type Err = ();
130
131    fn from_str(s: &str) -> Result<Self, Self::Err> {
132        match s {
133            "Boolean" => Ok(AttributeType::Boolean),
134            "Binary" => Ok(AttributeType::Binary),
135            "Text" => Ok(AttributeType::Text),
136            "Numeric" => Ok(AttributeType::Numeric),
137            "DateTime" => Ok(AttributeType::DateTime),
138            _ => Err(()),
139        }
140    }
141}
142
143#[derive(Debug, PartialEq, Eq, Hash, Clone)]
144pub enum OverlayType {
145    Label,
146    Information,
147    Encoding,
148    CharacterEncoding,
149    Format,
150    Meta,
151    Standard,
152    Cardinality,
153    Conditional,
154    Conformance,
155    EntryCode,
156    Entry,
157    Unit,
158    AttributeMapping,
159    EntryCodeMapping,
160    Subset,
161    UnitMapping,
162    Layout,
163    Sensitivity,
164}
165
166impl Serialize for OverlayType {
167    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
168    where
169        S: Serializer,
170    {
171        match self {
172            OverlayType::Label => serializer.serialize_str("spec/overlays/label/1.0"),
173            OverlayType::Information => serializer.serialize_str("spec/overlays/information/1.0"),
174            OverlayType::Encoding => serializer.serialize_str("spec/overlays/encoding/1.0"),
175            OverlayType::CharacterEncoding => {
176                serializer.serialize_str("spec/overlays/character_encoding/1.0")
177            }
178            OverlayType::Format => serializer.serialize_str("spec/overlays/format/1.0"),
179            OverlayType::Meta => serializer.serialize_str("spec/overlays/meta/1.0"),
180            OverlayType::Standard => serializer.serialize_str("spec/overlays/standard/1.0"),
181            OverlayType::Cardinality => serializer.serialize_str("spec/overlays/cardinality/1.0"),
182            OverlayType::Conditional => serializer.serialize_str("spec/overlays/conditional/1.0"),
183            OverlayType::Conformance => serializer.serialize_str("spec/overlays/conformance/1.0"),
184            OverlayType::EntryCode => serializer.serialize_str("spec/overlays/entry_code/1.0"),
185            OverlayType::Entry => serializer.serialize_str("spec/overlays/entry/1.0"),
186            OverlayType::Unit => serializer.serialize_str("spec/overlays/unit/1.0"),
187            OverlayType::AttributeMapping => serializer.serialize_str("spec/overlays/mapping/1.0"),
188            OverlayType::EntryCodeMapping => {
189                serializer.serialize_str("spec/overlays/entry_code_mapping/1.0")
190            }
191            OverlayType::Subset => serializer.serialize_str("spec/overlays/subset/1.0"),
192            OverlayType::UnitMapping => serializer.serialize_str("spec/overlays/unit_mapping/1.0"),
193            OverlayType::Layout => serializer.serialize_str("spec/overlays/layout/1.0"),
194            OverlayType::Sensitivity => serializer.serialize_str("spec/overlays/sensitivity/1.0"),
195        }
196    }
197}
198
199impl Serialize for ObjectKind {
200    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
201    where
202        S: Serializer,
203    {
204        let mut state = serializer.serialize_struct("ObjectKind", 3)?;
205        match self {
206            ObjectKind::CaptureBase(content) => {
207                state.serialize_field("object_kind", "CaptureBase")?;
208                state.serialize_field("content", content)?;
209            }
210            ObjectKind::OCABundle(content) => {
211                state.serialize_field("object_kind", "OCABundle")?;
212                state.serialize_field("content", content)?;
213            }
214            ObjectKind::Overlay(overlay_type, content) => {
215                // Convert OverlayType to a string representation
216                let overlay_type_str = overlay_type.to_string();
217                state.serialize_field("object_kind", &overlay_type_str)?;
218                state.serialize_field("content", content)?;
219            }
220        }
221        state.end()
222    }
223}
224
225impl FromStr for OverlayType {
226    type Err = ();
227
228    fn from_str(s: &str) -> Result<Self, Self::Err> {
229        match s {
230            "Label" => Ok(OverlayType::Label),
231            "Information" => Ok(OverlayType::Information),
232            "Encoding" => Ok(OverlayType::Encoding),
233            "CharacterEncoding" => Ok(OverlayType::CharacterEncoding),
234            "Format" => Ok(OverlayType::Format),
235            "Meta" => Ok(OverlayType::Meta),
236            "Standard" => Ok(OverlayType::Standard),
237            "Cardinality" => Ok(OverlayType::Cardinality),
238            "Conditional" => Ok(OverlayType::Conditional),
239            "Conformance" => Ok(OverlayType::Conformance),
240            "EntryCode" => Ok(OverlayType::EntryCode),
241            "Entry" => Ok(OverlayType::Entry),
242            "Unit" => Ok(OverlayType::Unit),
243            "Mapping" => Ok(OverlayType::AttributeMapping),
244            "EntryCodeMapping" => Ok(OverlayType::EntryCodeMapping),
245            "Subset" => Ok(OverlayType::Subset),
246            "UnitMapping" => Ok(OverlayType::UnitMapping),
247            "Layout" => Ok(OverlayType::Layout),
248            "Sensitivity" => Ok(OverlayType::Sensitivity),
249            _ => Err(()),
250        }
251    }
252}
253
254impl fmt::Display for OverlayType {
255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256        match self {
257            OverlayType::Label => write!(f, "Label"),
258            OverlayType::Information => write!(f, "Information"),
259            OverlayType::Encoding => write!(f, "Encoding"),
260            OverlayType::CharacterEncoding => write!(f, "CharacterEncoding"),
261            OverlayType::Format => write!(f, "Format"),
262            OverlayType::Meta => write!(f, "Meta"),
263            OverlayType::Standard => write!(f, "Standard"),
264            OverlayType::Cardinality => write!(f, "Cardinality"),
265            OverlayType::Conditional => write!(f, "Conditional"),
266            OverlayType::Conformance => write!(f, "Conformance"),
267            OverlayType::EntryCode => write!(f, "EntryCode"),
268            OverlayType::Entry => write!(f, "Entry"),
269            OverlayType::Unit => write!(f, "Unit"),
270            OverlayType::AttributeMapping => write!(f, "AttributeMapping"),
271            OverlayType::EntryCodeMapping => write!(f, "EntryCodeMapping"),
272            OverlayType::Subset => write!(f, "Subset"),
273            OverlayType::UnitMapping => write!(f, "UnitMapping"),
274            OverlayType::Layout => write!(f, "Layout"),
275            OverlayType::Sensitivity => write!(f, "Sensitivity"),
276        }
277    }
278}
279
280impl<'de> Deserialize<'de> for OverlayType {
281    fn deserialize<D>(deserializer: D) -> Result<OverlayType, D::Error>
282    where
283        D: Deserializer<'de>,
284    {
285        let s = String::deserialize(deserializer)?;
286        match s.as_str() {
287            "spec/overlays/label/1.0" => Ok(OverlayType::Label),
288            "spec/overlays/information/1.0" => Ok(OverlayType::Information),
289            "spec/overlays/encoding/1.0" => Ok(OverlayType::Encoding),
290            "spec/overlays/character_encoding/1.0" => Ok(OverlayType::CharacterEncoding),
291            "spec/overlays/format/1.0" => Ok(OverlayType::Format),
292            "spec/overlays/meta/1.0" => Ok(OverlayType::Meta),
293            "spec/overlays/standard/1.0" => Ok(OverlayType::Standard),
294            "spec/overlays/cardinality/1.0" => Ok(OverlayType::Cardinality),
295            "spec/overlays/conditional/1.0" => Ok(OverlayType::Conditional),
296            "spec/overlays/conformance/1.0" => Ok(OverlayType::Conformance),
297            "spec/overlays/entry_code/1.0" => Ok(OverlayType::EntryCode),
298            "spec/overlays/entry/1.0" => Ok(OverlayType::Entry),
299            "spec/overlays/unit/1.0" => Ok(OverlayType::Unit),
300            "spec/overlays/mapping/1.0" => Ok(OverlayType::AttributeMapping),
301            "spec/overlays/entry_code_mapping/1.0" => Ok(OverlayType::EntryCodeMapping),
302            "spec/overlays/subset/1.0" => Ok(OverlayType::Subset),
303            "spec/overlays/unit_mapping/1.0" => Ok(OverlayType::UnitMapping),
304            "spec/overlays/layout/1.0" => Ok(OverlayType::Layout),
305            "spec/overlays/sensitivity/1.0" => Ok(OverlayType::Sensitivity),
306            _ => Err(serde::de::Error::custom(format!(
307                "unknown overlay type: {}",
308                s
309            ))),
310        }
311    }
312}
313
314#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq, Hash)]
315pub struct BundleContent {
316    pub said: ReferenceAttrType,
317}
318
319#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq)]
320pub struct CaptureContent {
321    #[serde(skip_serializing_if = "Option::is_none")]
322    pub attributes: Option<IndexMap<String, NestedAttrType>>,
323    #[serde(skip_serializing_if = "Option::is_none")]
324    pub properties: Option<IndexMap<String, NestedValue>>,
325    #[serde(skip_serializing_if = "Option::is_none")]
326    pub flagged_attributes: Option<Vec<String>>,
327}
328
329// TODO remove it when moved all to BaseAttributeContent
330#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq)]
331pub struct Content {
332    #[serde(skip_serializing_if = "Option::is_none")]
333    pub attributes: Option<IndexMap<String, NestedValue>>,
334    #[serde(skip_serializing_if = "Option::is_none")]
335    pub properties: Option<IndexMap<String, NestedValue>>,
336}
337
338#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq, Hash)]
339#[serde(untagged)]
340/// Enum representing type supported in bundle (From command)
341///
342/// References: supports ref said and ref name
343pub enum ReferenceAttrType {
344    Reference(RefValue),
345}
346
347#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Eq)]
348#[serde(untagged)]
349pub enum NestedValue {
350    Reference(RefValue),
351    Value(String),
352    Object(IndexMap<String, NestedValue>),
353    Array(Vec<NestedValue>),
354}
355impl NestedValue {
356    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
357        match self {
358            NestedValue::Reference(ref_value) => {
359                ref_value.hash(state);
360            }
361            NestedValue::Value(value) => {
362                value.hash(state);
363            }
364            NestedValue::Object(object) => {
365                for (key, value) in object {
366                    key.hash(state);
367                    value.hash(state);
368                }
369            }
370            NestedValue::Array(array) => {
371                for value in array {
372                    value.hash(state);
373                }
374            }
375        }
376    }
377}
378
379#[derive(Debug, PartialEq, Clone, Hash, Eq)]
380pub enum RefValue {
381    Said(said::SelfAddressingIdentifier),
382    // This type is supported only for local-reference feature from facade (oca)
383    Name(String),
384}
385
386impl FromStr for RefValue {
387    type Err = RefValueParsingError;
388
389    fn from_str(s: &str) -> Result<Self, Self::Err> {
390        let (tag, rest) = s
391            .split_once(':')
392            .ok_or(RefValueParsingError::MissingColon)?;
393        match tag {
394            "refs" => {
395                let said = SelfAddressingIdentifier::from_str(rest)?;
396                Ok(RefValue::Said(said))
397            }
398            "refn" => Ok(RefValue::Name(rest.to_string())),
399            _ => Err(RefValueParsingError::UnknownTag(tag.to_string())),
400        }
401    }
402}
403
404#[derive(Error, Debug)]
405
406pub enum RefValueParsingError {
407    #[error("Missing colon")]
408    MissingColon,
409    #[error("Unknown tag `{0}`. Referece need to start with `refs` od `refn`")]
410    UnknownTag(String),
411    #[error("Invalid said: {0}")]
412    SaidError(#[from] said::error::Error),
413}
414
415impl fmt::Display for RefValue {
416    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
417        match &self {
418            RefValue::Said(said) => write!(f, "refs:{}", said),
419            RefValue::Name(name) => write!(f, "refn:{}", name),
420        }
421    }
422}
423impl Serialize for RefValue {
424    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
425    where
426        S: Serializer,
427    {
428        match &self {
429            RefValue::Said(said) => serializer.serialize_str(format!("refs:{}", said).as_str()),
430            RefValue::Name(name) => serializer.serialize_str(format!("refn:{}", name).as_str()),
431        }
432    }
433}
434
435// Implement Deserialize for Command
436impl<'de> Deserialize<'de> for Command {
437    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
438    where
439        D: Deserializer<'de>,
440    {
441        enum Field {
442            Kind,
443            ObjectKind,
444        }
445
446        impl<'de> Deserialize<'de> for Field {
447            fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
448            where
449                D: Deserializer<'de>,
450            {
451                struct FieldVisitor;
452
453                impl<'de> Visitor<'de> for FieldVisitor {
454                    type Value = Field;
455
456                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
457                        formatter.write_str("`type` or `object_kind`")
458                    }
459
460                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
461                    where
462                        E: de::Error,
463                    {
464                        match value {
465                            "type" => Ok(Field::Kind),
466                            "object_kind" => Ok(Field::ObjectKind),
467                            _ => Err(de::Error::unknown_field(value, FIELDS)),
468                        }
469                    }
470                }
471
472                deserializer.deserialize_identifier(FieldVisitor)
473            }
474        }
475
476        struct CommandVisitor;
477
478        impl<'de> Visitor<'de> for CommandVisitor {
479            type Value = Command;
480
481            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
482                formatter.write_str("struct Command")
483            }
484
485            fn visit_map<V>(self, mut map: V) -> Result<Command, V::Error>
486            where
487                V: MapAccess<'de>,
488            {
489                let mut kind = None;
490                let mut object_kind = None;
491
492                while let Some(key) = map.next_key()? {
493                    match key {
494                        Field::Kind => {
495                            if kind.is_some() {
496                                return Err(de::Error::duplicate_field("type"));
497                            }
498                            kind = Some(map.next_value()?);
499                        }
500                        Field::ObjectKind => {
501                            if object_kind.is_some() {
502                                return Err(de::Error::duplicate_field("object_kind"));
503                            }
504                            let object_kind_str: String = map.next_value()?;
505                            match object_kind_str.as_str() {
506                                "CaptureBase" => {
507                                    // take the key frist otherwise next value would not work
508                                    // properly
509                                    let _content_key: Option<String> = map.next_key()?;
510                                    let content: CaptureContent = map.next_value()?;
511                                    object_kind = Some(ObjectKind::CaptureBase(content));
512                                }
513                                "OCABundle" => {
514                                    // take the key frist otherwise next value would not work
515                                    // properly
516                                    let _content_key: Option<String> = map.next_key()?;
517                                    let content: BundleContent = map.next_value()?;
518                                    object_kind = Some(ObjectKind::OCABundle(content));
519                                }
520                                _ => {
521                                    // take the key frist otherwise next value would not work
522                                    // properly
523                                    let _content_key: Option<String> = map.next_key()?;
524                                    // if it is not a CaptureBase or OCABundle, it must be an Overlay
525                                    let overlay_type =
526                                        OverlayType::from_str(object_kind_str.as_str());
527                                    match overlay_type {
528                                        Ok(overlay_type) => {
529                                            let content: Content = map.next_value()?;
530                                            object_kind =
531                                                Some(ObjectKind::Overlay(overlay_type, content));
532                                        }
533                                        Err(_) => {
534                                            return Err(de::Error::unknown_field(
535                                                &object_kind_str,
536                                                VARIANTS,
537                                            ))
538                                        }
539                                    }
540                                }
541                            }
542                        }
543                    }
544                }
545
546                let kind = kind.ok_or_else(|| de::Error::missing_field("type"))?;
547                let object_kind =
548                    object_kind.ok_or_else(|| de::Error::missing_field("object_kind"))?;
549
550                Ok(Command { kind, object_kind })
551            }
552        }
553
554        const FIELDS: &[&str] = &["type", "object_kind", "content"];
555        const VARIANTS: &[&str] = &["CaptureBase", "OCABundle", "Overlay"];
556        deserializer.deserialize_struct("Command", FIELDS, CommandVisitor)
557    }
558}
559
560impl<'de> Deserialize<'de> for RefValue {
561    fn deserialize<D>(deserializer: D) -> Result<RefValue, D::Error>
562    where
563        D: Deserializer<'de>,
564    {
565        let s = String::deserialize(deserializer)?;
566        let (tag, rest) = s.split_once(':').ok_or(serde::de::Error::custom(format!(
567            "invalid reference: {}",
568            s
569        )))?;
570        match tag {
571            "refs" => {
572                let said = SelfAddressingIdentifier::from_str(rest);
573                match said {
574                    Ok(said) => Ok(RefValue::Said(said)),
575                    Err(_) => Err(serde::de::Error::custom(format!(
576                        "invalid reference: {}",
577                        s
578                    ))),
579                }
580            }
581            "refn" => Ok(RefValue::Name(rest.to_string())),
582            _ => Err(serde::de::Error::custom(format!(
583                "unknown reference type: {}",
584                tag
585            ))),
586        }
587    }
588}
589
590impl OCAAst {
591    pub fn new() -> Self {
592        OCAAst {
593            // Version of OCA specification
594            version: String::from("1.0.0"),
595            commands: Vec::new(),
596            commands_meta: IndexMap::new(),
597            meta: HashMap::new(),
598        }
599    }
600}
601
602impl Default for OCAAst {
603    fn default() -> Self {
604        Self::new()
605    }
606}
607
608/*
609impl Serialize for ObjectKind {
610    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
611    where
612        S: Serializer,
613    {
614        match self {
615            ObjectKind::CaptureBase => serializer.serialize_str("CaptureBase"),
616            ObjectKind::OCABundle => serializer.serialize_str("OCABundle"),
617            ObjectKind::Overlay(overlay_type) => {
618                serializer.serialize_str(overlay_type.to_string().as_str())
619            }
620        }
621    }
622}*/
623
624impl From<u8> for ObjectKind {
625    fn from(val: u8) -> Self {
626        match val {
627            0 => ObjectKind::CaptureBase(CaptureContent {
628                attributes: None,
629                properties: None,
630                flagged_attributes: None,
631            }),
632            1 => ObjectKind::OCABundle(BundleContent {
633                said: ReferenceAttrType::Reference(RefValue::Name("".to_string())),
634            }),
635            2 => ObjectKind::Overlay(
636                OverlayType::Label,
637                Content {
638                    attributes: None,
639                    properties: None,
640                },
641            ),
642            3 => ObjectKind::Overlay(
643                OverlayType::Information,
644                Content {
645                    attributes: None,
646                    properties: None,
647                },
648            ),
649            4 => ObjectKind::Overlay(
650                OverlayType::Encoding,
651                Content {
652                    attributes: None,
653                    properties: None,
654                },
655            ),
656            5 => ObjectKind::Overlay(
657                OverlayType::CharacterEncoding,
658                Content {
659                    attributes: None,
660                    properties: None,
661                },
662            ),
663            6 => ObjectKind::Overlay(
664                OverlayType::Format,
665                Content {
666                    attributes: None,
667                    properties: None,
668                },
669            ),
670            7 => ObjectKind::Overlay(
671                OverlayType::Meta,
672                Content {
673                    attributes: None,
674                    properties: None,
675                },
676            ),
677            8 => ObjectKind::Overlay(
678                OverlayType::Standard,
679                Content {
680                    attributes: None,
681                    properties: None,
682                },
683            ),
684            9 => ObjectKind::Overlay(
685                OverlayType::Cardinality,
686                Content {
687                    attributes: None,
688                    properties: None,
689                },
690            ),
691            10 => ObjectKind::Overlay(
692                OverlayType::Conditional,
693                Content {
694                    attributes: None,
695                    properties: None,
696                },
697            ),
698            11 => ObjectKind::Overlay(
699                OverlayType::Conformance,
700                Content {
701                    attributes: None,
702                    properties: None,
703                },
704            ),
705            12 => ObjectKind::Overlay(
706                OverlayType::EntryCode,
707                Content {
708                    attributes: None,
709                    properties: None,
710                },
711            ),
712            13 => ObjectKind::Overlay(
713                OverlayType::Entry,
714                Content {
715                    attributes: None,
716                    properties: None,
717                },
718            ),
719            14 => ObjectKind::Overlay(
720                OverlayType::Unit,
721                Content {
722                    attributes: None,
723                    properties: None,
724                },
725            ),
726            15 => ObjectKind::Overlay(
727                OverlayType::AttributeMapping,
728                Content {
729                    attributes: None,
730                    properties: None,
731                },
732            ),
733            16 => ObjectKind::Overlay(
734                OverlayType::EntryCodeMapping,
735                Content {
736                    attributes: None,
737                    properties: None,
738                },
739            ),
740            17 => ObjectKind::Overlay(
741                OverlayType::Subset,
742                Content {
743                    attributes: None,
744                    properties: None,
745                },
746            ),
747            18 => ObjectKind::Overlay(
748                OverlayType::UnitMapping,
749                Content {
750                    attributes: None,
751                    properties: None,
752                },
753            ),
754            19 => ObjectKind::Overlay(
755                OverlayType::Layout,
756                Content {
757                    attributes: None,
758                    properties: None,
759                },
760            ),
761            20 => ObjectKind::Overlay(
762                OverlayType::Sensitivity,
763                Content {
764                    attributes: None,
765                    properties: None,
766                },
767            ),
768            _ => panic!("Unknown object type"),
769        }
770    }
771}
772
773impl From<ObjectKind> for u8 {
774    fn from(val: ObjectKind) -> Self {
775        match val {
776            ObjectKind::CaptureBase(_) => 0,
777            ObjectKind::OCABundle(_) => 1,
778            ObjectKind::Overlay(OverlayType::Label, _) => 2,
779            ObjectKind::Overlay(OverlayType::Information, _) => 3,
780            ObjectKind::Overlay(OverlayType::Encoding, _) => 4,
781            ObjectKind::Overlay(OverlayType::CharacterEncoding, _) => 5,
782            ObjectKind::Overlay(OverlayType::Format, _) => 6,
783            ObjectKind::Overlay(OverlayType::Meta, _) => 7,
784            ObjectKind::Overlay(OverlayType::Standard, _) => 8,
785            ObjectKind::Overlay(OverlayType::Cardinality, _) => 9,
786            ObjectKind::Overlay(OverlayType::Conditional, _) => 10,
787            ObjectKind::Overlay(OverlayType::Conformance, _) => 11,
788            ObjectKind::Overlay(OverlayType::EntryCode, _) => 12,
789            ObjectKind::Overlay(OverlayType::Entry, _) => 13,
790            ObjectKind::Overlay(OverlayType::Unit, _) => 14,
791            ObjectKind::Overlay(OverlayType::AttributeMapping, _) => 15,
792            ObjectKind::Overlay(OverlayType::EntryCodeMapping, _) => 16,
793            ObjectKind::Overlay(OverlayType::Subset, _) => 17,
794            ObjectKind::Overlay(OverlayType::UnitMapping, _) => 18,
795            ObjectKind::Overlay(OverlayType::Layout, _) => 19,
796            ObjectKind::Overlay(OverlayType::Sensitivity, _) => 20,
797        }
798    }
799}
800
801impl<'de> Deserialize<'de> for ObjectKind {
802    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
803    where
804        D: Deserializer<'de>,
805    {
806        let s = String::deserialize(deserializer)?;
807        match s.as_str() {
808            "CaptureBase" => Ok(ObjectKind::CaptureBase(CaptureContent {
809                attributes: None,
810                properties: None,
811                flagged_attributes: None,
812            })),
813            "OCABundle" => Ok(ObjectKind::OCABundle(BundleContent {
814                said: ReferenceAttrType::Reference(RefValue::Name("".to_string())),
815            })),
816            "Label" => Ok(ObjectKind::Overlay(
817                OverlayType::Label,
818                Content {
819                    attributes: None,
820                    properties: None,
821                },
822            )),
823            "Information" => Ok(ObjectKind::Overlay(
824                OverlayType::Information,
825                Content {
826                    attributes: None,
827                    properties: None,
828                },
829            )),
830            "Encoding" => Ok(ObjectKind::Overlay(
831                OverlayType::Encoding,
832                Content {
833                    attributes: None,
834                    properties: None,
835                },
836            )),
837            "CharacterEncoding" => Ok(ObjectKind::Overlay(
838                OverlayType::CharacterEncoding,
839                Content {
840                    attributes: None,
841                    properties: None,
842                },
843            )),
844            "Format" => Ok(ObjectKind::Overlay(
845                OverlayType::Format,
846                Content {
847                    attributes: None,
848                    properties: None,
849                },
850            )),
851            "Meta" => Ok(ObjectKind::Overlay(
852                OverlayType::Meta,
853                Content {
854                    attributes: None,
855                    properties: None,
856                },
857            )),
858            "Standard" => Ok(ObjectKind::Overlay(
859                OverlayType::Standard,
860                Content {
861                    attributes: None,
862                    properties: None,
863                },
864            )),
865            "Cardinality" => Ok(ObjectKind::Overlay(
866                OverlayType::Cardinality,
867                Content {
868                    attributes: None,
869                    properties: None,
870                },
871            )),
872            "Conditional" => Ok(ObjectKind::Overlay(
873                OverlayType::Conditional,
874                Content {
875                    attributes: None,
876                    properties: None,
877                },
878            )),
879            "Conformance" => Ok(ObjectKind::Overlay(
880                OverlayType::Conformance,
881                Content {
882                    attributes: None,
883                    properties: None,
884                },
885            )),
886            "EntryCode" => Ok(ObjectKind::Overlay(
887                OverlayType::EntryCode,
888                Content {
889                    attributes: None,
890                    properties: None,
891                },
892            )),
893            "Entry" => Ok(ObjectKind::Overlay(
894                OverlayType::Entry,
895                Content {
896                    attributes: None,
897                    properties: None,
898                },
899            )),
900            "Unit" => Ok(ObjectKind::Overlay(
901                OverlayType::Unit,
902                Content {
903                    attributes: None,
904                    properties: None,
905                },
906            )),
907            "AttributeMapping" => Ok(ObjectKind::Overlay(
908                OverlayType::AttributeMapping,
909                Content {
910                    attributes: None,
911                    properties: None,
912                },
913            )),
914            "EntryCodeMapping" => Ok(ObjectKind::Overlay(
915                OverlayType::EntryCodeMapping,
916                Content {
917                    attributes: None,
918                    properties: None,
919                },
920            )),
921            "Subset" => Ok(ObjectKind::Overlay(
922                OverlayType::Subset,
923                Content {
924                    attributes: None,
925                    properties: None,
926                },
927            )),
928            "UnitMapping" => Ok(ObjectKind::Overlay(
929                OverlayType::UnitMapping,
930                Content {
931                    attributes: None,
932                    properties: None,
933                },
934            )),
935            "Layout" => Ok(ObjectKind::Overlay(
936                OverlayType::Layout,
937                Content {
938                    attributes: None,
939                    properties: None,
940                },
941            )),
942            "Sensitivity" => Ok(ObjectKind::Overlay(
943                OverlayType::Sensitivity,
944                Content {
945                    attributes: None,
946                    properties: None,
947                },
948            )),
949            _ => Err(serde::de::Error::custom(format!(
950                "unknown object kind: {}",
951                s
952            ))),
953        }
954    }
955}
956
957#[cfg(test)]
958mod tests {
959    use super::*;
960
961    #[test]
962    fn test_ocaast_serialize() {
963        let mut attributes = IndexMap::new();
964        let mut properties = IndexMap::new();
965        let mut flagged_attributes = Vec::new();
966
967        let arr = NestedAttrType::Array(Box::new(NestedAttrType::Value(AttributeType::Boolean)));
968        attributes.insert("allowed".to_string(), arr);
969        attributes.insert(
970            "test".to_string(),
971            NestedAttrType::Value(AttributeType::Text),
972        );
973
974        flagged_attributes.push("test".to_string());
975        properties.insert("test".to_string(), NestedValue::Value("test".to_string()));
976        let command = Command {
977            kind: CommandType::Add,
978            object_kind: ObjectKind::CaptureBase(CaptureContent {
979                attributes: Some(attributes),
980                properties: Some(properties),
981                flagged_attributes: flagged_attributes.into(),
982            }),
983        };
984
985        let lable_command = Command {
986            kind: CommandType::Add,
987            object_kind: ObjectKind::Overlay(
988                OverlayType::Label,
989                Content {
990                    attributes: None,
991                    properties: None,
992                },
993            ),
994        };
995
996        let mut ocaast = OCAAst::new();
997        ocaast.commands.push(command);
998        ocaast.commands.push(lable_command);
999
1000        let serialized = serde_json::to_string(&ocaast).unwrap();
1001        assert_eq!(
1002            serialized,
1003            r#"{"version":"1.0.0","commands":[{"type":"Add","object_kind":"CaptureBase","content":{"attributes":{"allowed":["Boolean"],"test":"Text"},"properties":{"test":"test"},"flagged_attributes":["test"]}},{"type":"Add","object_kind":"Label","content":{}}],"commands_meta":{},"meta":{}}"#
1004        );
1005
1006        let deser: OCAAst = serde_json::from_str(&serialized).unwrap();
1007        assert_eq!(ocaast, deser);
1008    }
1009}