1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
pub mod attribute_mapping;
pub mod cardinality;
pub mod character_encoding;
pub mod conditional;
pub mod conformance;
pub mod credential_layout;
pub mod entry;
pub mod entry_code;
pub mod entry_code_mapping;
pub mod form_layout;
#[cfg(feature = "format_overlay")]
pub mod format;
pub mod information;
pub mod label;
pub mod meta;
pub mod standard;
pub mod subset;
pub mod unit;

pub use self::attribute_mapping::AttributeMappingOverlay as AttributeMapping;
pub use self::cardinality::CardinalityOverlay as Cardinality;
pub use self::character_encoding::CharacterEncodingOverlay as CharacterEncoding;
pub use self::conditional::ConditionalOverlay as Conditional;
pub use self::conformance::ConformanceOverlay as Conformance;
pub use self::credential_layout::CredentialLayoutOverlay as CredentialLayout;
pub use self::entry::EntryOverlay as Entry;
pub use self::entry_code::EntryCodeOverlay as EntryCode;
pub use self::entry_code_mapping::EntryCodeMappingOverlay as EntryCodeMapping;
pub use self::form_layout::FormLayoutOverlay as FormLayout;
#[cfg(feature = "format_overlay")]
pub use self::format::FormatOverlay as Format;
pub use self::information::InformationOverlay as Information;
pub use self::label::LabelOverlay as Label;
pub use self::meta::MetaOverlay as Meta;
pub use self::standard::StandardOverlay as Standard;
pub use self::subset::SubsetOverlay as Subset;
pub use oca_ast_semantics::ast::OverlayType;
use said::derivation::HashFunctionCode;

pub use self::unit::UnitOverlay as Unit;
use crate::state::attribute::Attribute;
use isolang::Language;
use said::sad::{SerializationFormats, SAD};
use std::any::Any;
erased_serde::serialize_trait_object!(Overlay);

use dyn_clonable::*;

#[clonable]
pub trait Overlay: erased_serde::Serialize + Clone + SAD {
    fn as_any(&self) -> &dyn Any;
    fn capture_base(&self) -> &Option<said::SelfAddressingIdentifier>;
    fn set_capture_base(&mut self, said: &said::SelfAddressingIdentifier);
    fn said(&self) -> &Option<said::SelfAddressingIdentifier>;
    fn overlay_type(&self) -> &OverlayType;
    fn language(&self) -> Option<&Language> {
        None
    }

    fn attributes(&self) -> Vec<&String>;

    fn add(&mut self, attribute: &Attribute);

    fn fill_said(&mut self) {
        let code = HashFunctionCode::Blake3_256;
        let format = SerializationFormats::JSON;
        self.compute_digest(&code, &format);
    }

    fn sign(&mut self, capture_base_sai: &said::SelfAddressingIdentifier) {
        self.set_capture_base(capture_base_sai);
        self.fill_said();
    }
}

macro_rules! overlay {
    ($name:ident, $field1:ident, $field2:ident: $field2_type:ty) => {
        paste::paste! {
            pub trait [<$name s>] {
                fn [<set_ $field2>](&mut self, $field2: $field2_type);
            }

            impl [<$name s>] for crate::state::attribute::Attribute {
                fn [<set_ $field2>](&mut self, $field2: $field2_type) {
                    self.$field2 = Some($field2);
                }
            }

            pub fn serialize_attributes<S>(attributes: &std::collections::HashMap<String, $field2_type>, s: S) -> Result<S::Ok, S::Error>
            where
                S: serde::Serializer,
            {
                use std::collections::BTreeMap;

                let mut ser = s.serialize_map(Some(attributes.len()))?;
                let sorted_attributes: BTreeMap<_, _> = attributes.iter().collect();
                for (k, v) in sorted_attributes {
                    ser.serialize_entry(k, v)?;
                }
                ser.end()
            }

            #[derive(serde::Deserialize, serde::Serialize, SAD, Debug, Clone)]
            pub struct [<$name Overlay>] {
                #[said]
                #[serde(rename = "d")]
                said: Option<said::SelfAddressingIdentifier>,
                #[serde(rename = "type")]
                overlay_type: oca_ast_semantics::ast::OverlayType,
                capture_base: Option<said::SelfAddressingIdentifier>,
                #[serde(serialize_with = "serialize_attributes")]
                pub $field1: std::collections::HashMap<String, $field2_type>
            }

            impl crate::state::oca::overlay::Overlay for [<$name Overlay>] {
                fn as_any(&self) -> &dyn std::any::Any {
                    self
                }
                fn overlay_type(&self) -> &oca_ast_semantics::ast::OverlayType {
                    &self.overlay_type
                }
                fn capture_base(&self) -> &Option<said::SelfAddressingIdentifier> {
                    &self.capture_base
                }
                fn set_capture_base(&mut self, said: &said::SelfAddressingIdentifier) {
                    self.capture_base = Some(said.clone());
                }
                fn said(&self) -> &Option<said::SelfAddressingIdentifier> {
                    &self.said
                }
                fn attributes(&self) -> Vec<&String> {
                    self.$field1.keys().collect::<Vec<&String>>()
                }

                fn add(&mut self, attribute: &crate::state::attribute::Attribute) {
                    if attribute.$field2.is_some() {
                        self.$field1.insert(attribute.name.clone(), attribute.$field2.clone().unwrap());
                    }
                }
            }

            impl Default for [<$name Overlay>] {
                fn default() -> Self {
                    Self::new()
                }
            }

            impl [<$name Overlay>] {
                pub fn new() -> Self {
                    Self {
                        capture_base: None,
                        said: None,
                        overlay_type: oca_ast_semantics::ast::OverlayType::$name,
                        $field1: std::collections::HashMap::new(),

                    }
                }
            }
        }
    }
}
pub(crate) use overlay;