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