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 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 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#[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)]
385pub 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 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
484impl<'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 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 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 let _content_key: Option<String> =
584 map.next_key()?;
585 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: 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}