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 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 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#[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)]
340pub 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 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
435impl<'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 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 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 let _content_key: Option<String> = map.next_key()?;
524 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: 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
608impl 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}