oca_bundle_semantics/state/oca/overlay/
attribute_framing.rs1use crate::state::{attribute::Attribute, oca::Overlay};
2use isolang::Language;
3use oca_ast_semantics::ast::OverlayType;
4use said::derivation::HashFunctionCode;
5use said::{sad::SerializationFormats, sad::SAD};
6use serde::{ser::SerializeMap, Deserialize, Serialize, Serializer};
7use std::any::Any;
8use std::collections::HashMap;
9
10pub type Framing = HashMap<String, FramingScope>;
11
12#[derive(Serialize, Deserialize, Debug, Clone)]
13pub struct FramingScope {
14 pub predicate_id: String,
15 pub framing_justification: String,
16 #[serde(skip)]
17 pub frame_meta: HashMap<String, String>,
18}
19
20pub trait Framings {
21 fn set_framing(&mut self, id: String, framing: Framing);
22}
23
24impl Framings for Attribute {
25 fn set_framing(&mut self, id: String, framing: Framing) {
26 match self.framings {
27 Some(ref mut framings) => {
28 if let Some(f) = framings.get_mut(&id) {
29 f.extend(framing);
30 } else {
31 framings.insert(id, framing);
32 }
33 }
34 None => {
35 let mut framings = HashMap::new();
36 framings.insert(id, framing);
37 self.framings = Some(framings);
38 }
39 }
40 }
41}
42
43pub fn serialize_metadata<S>(metadata: &HashMap<String, String>, s: S) -> Result<S::Ok, S::Error>
44where
45 S: Serializer,
46{
47 use std::collections::BTreeMap;
48
49 let mut ser = s.serialize_map(Some(metadata.len()))?;
50 let sorted_metadata: BTreeMap<_, _> = metadata.iter().collect();
51 for (k, v) in sorted_metadata {
52 ser.serialize_entry(k, v)?;
53 }
54 ser.end()
55}
56
57pub fn serialize_framing<S>(attributes: &HashMap<String, Framing>, s: S) -> Result<S::Ok, S::Error>
58where
59 S: Serializer,
60{
61 use std::collections::BTreeMap;
62
63 let mut ser = s.serialize_map(Some(attributes.len()))?;
64 let sorted_attributes: BTreeMap<_, _> = attributes.iter().collect();
65 for (k, v) in sorted_attributes {
66 let sorted_framings: BTreeMap<_, _> = v.iter().collect();
67 ser.serialize_entry(k, &sorted_framings)?;
68 }
69 ser.end()
70}
71
72#[derive(SAD, Serialize, Deserialize, Debug, Clone)]
73pub struct AttributeFramingOverlay {
74 #[said]
75 #[serde(rename = "d")]
76 said: Option<said::SelfAddressingIdentifier>,
77 capture_base: Option<said::SelfAddressingIdentifier>,
78 #[serde(rename = "type")]
79 overlay_type: OverlayType,
80 #[serde(rename = "framing_metadata", serialize_with = "serialize_metadata")]
81 pub metadata: HashMap<String, String>,
82 #[serde(serialize_with = "serialize_framing")]
83 pub attribute_framing: HashMap<String, Framing>,
84}
85
86impl Overlay for AttributeFramingOverlay {
87 fn as_any(&self) -> &dyn Any {
88 self
89 }
90 fn capture_base(&self) -> &Option<said::SelfAddressingIdentifier> {
91 &self.capture_base
92 }
93 fn set_capture_base(&mut self, said: &said::SelfAddressingIdentifier) {
94 self.capture_base = Some(said.clone());
95 }
96 fn overlay_type(&self) -> &OverlayType {
97 &self.overlay_type
98 }
99 fn said(&self) -> &Option<said::SelfAddressingIdentifier> {
100 &self.said
101 }
102 fn language(&self) -> Option<&Language> {
103 None
104 }
105 fn attributes(&self) -> Vec<&String> {
106 self.attribute_framing.keys().collect::<Vec<&String>>()
107 }
108 fn add(&mut self, attribute: &Attribute) {
111 if let Some(id) = self.metadata.get("frame_id") {
112 if let Some(framing) = &attribute.framings {
113 if let Some(value) = framing.get(id) {
114 self.attribute_framing
115 .insert(attribute.name.clone(), value.clone());
116
117 for framing_scope in value.values() {
118 for (k, v) in framing_scope.frame_meta.iter() {
119 self.metadata.insert(k.clone(), v.clone());
120 }
121 }
122 }
123 }
124 }
125 }
126}
127
128impl AttributeFramingOverlay {
129 pub fn new(id: String) -> Self {
130 let mut metadata = HashMap::new();
131 metadata.insert("frame_id".to_string(), id);
132 let overlay_version = "1.1".to_string();
133 Self {
134 capture_base: None,
135 said: None,
136 overlay_type: OverlayType::AttributeFraming(overlay_version),
137 metadata,
138 attribute_framing: HashMap::new(),
139 }
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn create_attribute_framing_overlay() {
149 let mut overlay = AttributeFramingOverlay::new("frame_id".to_string());
150 let mut loc1 = HashMap::new();
151 loc1.insert(
152 "http://loc.1".to_string(),
153 FramingScope {
154 predicate_id: "skos:exactMatch".to_string(),
155 framing_justification: "semapv:ManualMappingCuration".to_string(),
156 frame_meta: HashMap::new(),
157 },
158 );
159 let mut loc2 = HashMap::new();
160 loc2.insert(
161 "http://loc.2".to_string(),
162 FramingScope {
163 predicate_id: "skos:exactMatch".to_string(),
164 framing_justification: "semapv:ManualMappingCuration".to_string(),
165 frame_meta: HashMap::new(),
166 },
167 );
168 let attr = cascade! {
169 Attribute::new("attr1".to_string());
170 ..set_framing("frame_id".to_string(), loc1);
171 ..set_framing("frame_id".to_string(), loc2);
172 };
173 overlay.add(&attr);
175
176 let overlay_version = "1.1".to_string();
177 assert_eq!(overlay.overlay_type, OverlayType::AttributeFraming(overlay_version));
178 assert_eq!(overlay.attribute_framing.len(), 1);
179 }
180}