oca_ast_semantics/ast/
attributes.rs1use recursion::ExpandableExt;
2use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
3use std::hash::Hash;
4use wasm_bindgen::JsValue;
5
6use super::{
7 error::AttributeError,
8 recursive_attributes::{AttributeTypeResult, NestedAttrTypeFrame},
9 AttributeType, RefValue,
10};
11
12#[derive(Debug, PartialEq, Clone, Eq, Serialize)]
13#[serde(untagged)]
14pub enum NestedAttrType {
21 Reference(RefValue),
22 Value(AttributeType),
23 #[serde(serialize_with = "array_serializer")]
24 Array(Box<NestedAttrType>),
25 Null,
27}
28
29impl NestedAttrType {
30 pub fn to_js_value(&self) -> Result<JsValue, JsValue> {
31 Ok(serde_wasm_bindgen::to_value(self)?)
32 }
33
34 pub fn from_js_value(value: JsValue) -> Result<Self, JsValue> {
35 Ok(serde_wasm_bindgen::from_value(value)?)
36 }
37}
38
39fn array_serializer<S>(arr: &NestedAttrType, serializer: S) -> Result<S::Ok, S::Error>
40where
41 S: Serializer,
42{
43 let mut seq = serializer.serialize_seq(Some(1))?;
45 seq.serialize_element(&arr)?;
46 seq.end()
47
48 }
52
53impl Hash for NestedAttrType {
54 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
55 match self {
56 NestedAttrType::Reference(ref_value) => {
57 ref_value.hash(state);
58 }
59 NestedAttrType::Value(attr_type) => {
60 attr_type.hash(state);
61 }
62 NestedAttrType::Array(array) => {
63 array.hash(state);
64 }
65 NestedAttrType::Null => {
66 "null".hash(state);
67 }
68 }
69 }
70}
71
72impl<'de> Deserialize<'de> for NestedAttrType {
73 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
74 where
75 D: Deserializer<'de>,
76 {
77 let input: serde_json::Value = serde_json::Value::deserialize(deserializer)?;
78
79 let expanded = AttributeTypeResult::expand_frames(input, |seed| match seed {
80 serde_json::Value::Null => NestedAttrTypeFrame::Null.into(),
81 serde_json::Value::String(text) => match &text.get(..5) {
82 Some("refs:") | Some("refn:") => {
83 let res = text.parse::<RefValue>();
84 match res {
85 Ok(ref_value) => NestedAttrTypeFrame::Reference(ref_value).into(),
86 Err(e) => AttributeError::from(e).into(),
87 }
88 }
89 _ => {
90 let res = text.parse::<AttributeType>();
91 match res {
92 Ok(attr_type) => NestedAttrTypeFrame::Value(attr_type).into(),
93 Err(_) => AttributeError::UnknownAttributeType(text).into(),
94 }
95 }
96 },
97 serde_json::Value::Array(arr) => NestedAttrTypeFrame::Array(arr[0].clone()).into(),
98 value => {
99 AttributeError::ConvertingFailure(serde_json::to_string(&value).unwrap()).into()
100 }
101 });
102 match expanded.value() {
103 Ok(el) => Ok(el),
104 Err(er) => Err(serde::de::Error::custom(er)),
105 }
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use said::derivation::{HashFunction, HashFunctionCode};
112
113 use crate::ast::{error::AttributeError, AttributeType, NestedAttrType, RefValue};
114
115 #[test]
116 fn test_nested_array_attribute_type_serialization() {
117 let arr = NestedAttrType::Array(Box::new(NestedAttrType::Array(Box::new(
118 NestedAttrType::Value(AttributeType::Boolean),
119 ))));
120 let said = HashFunction::from(HashFunctionCode::Blake3_256).derive("fff".as_bytes());
121
122 let serialized = serde_json::to_string(&arr).unwrap();
123 let expected = r#"[["Boolean"]]"#;
124 assert_eq!(expected, serialized);
125
126 let deser: NestedAttrType = serde_json::from_str(&serialized).unwrap();
127 assert_eq!(arr, deser);
128
129 let attributes =
130 NestedAttrType::Array(Box::new(NestedAttrType::Reference(RefValue::Said(said))));
131
132 let serialized = serde_json::to_string(&attributes).unwrap();
133 let expected = r#"["refs:EEokfxxqwAM08iku7VHMaVFBaEGYVi2W-ctBKaTW6QdJ"]"#;
134 assert_eq!(expected, serialized);
135
136 let deser: NestedAttrType = serde_json::from_str(&serialized).unwrap();
137 assert_eq!(attributes, deser);
138 }
139
140 #[test]
141 fn test_nested_attribute_deserialize() {
142 let serialized = r#"["Numeric"]"#;
143 let deser: NestedAttrType = serde_json::from_str(serialized).unwrap();
144 assert_eq!(
145 NestedAttrType::Array(Box::new(NestedAttrType::Value(AttributeType::Numeric))),
146 deser
147 );
148
149 let wrong_type = r#"["Wrong"]"#;
150 let deser = serde_json::from_str::<NestedAttrType>(wrong_type);
151 assert!(deser.is_err());
152 assert_eq!(
153 deser.unwrap_err().to_string(),
154 AttributeError::UnknownAttributeType("Wrong".to_string()).to_string()
155 );
156
157 let serialized = r#"["refs:EEokfxxqwAM08iku7VHMaVFBaEGYVi2W-ctBKaTW6QdJ"]"#;
158 let expected = NestedAttrType::Array(Box::new(NestedAttrType::Reference(RefValue::Said(
159 said::derivation::HashFunction::from(said::derivation::HashFunctionCode::Blake3_256)
160 .derive("fff".as_bytes()),
161 ))));
162 let deser: NestedAttrType = serde_json::from_str(serialized).unwrap();
163 assert_eq!(expected, deser);
164
165 let serialized = r#"["refn:bob"]"#;
166 let expected = NestedAttrType::Array(Box::new(NestedAttrType::Reference(RefValue::Name(
167 "bob".to_string(),
168 ))));
169 let deser: NestedAttrType = serde_json::from_str(serialized).unwrap();
170 assert_eq!(expected, deser);
171 }
172
173 #[test]
174 fn test_reference_attribute_deserialize() {
175 let wrong_said = r#"["refs:wrong_said"]"#;
176 let deser = serde_json::from_str::<NestedAttrType>(wrong_said);
177 assert_eq!(deser.unwrap_err().to_string(), "Invalid said: Unknown code");
178
179 let missing_ref_tag = r#"["EEokfxxqwAM08iku7VHMaVFBaEGYVi2W-ctBKaTW6QdJ"]"#;
180 let deser = serde_json::from_str::<NestedAttrType>(missing_ref_tag);
181 assert_eq!(
182 deser.unwrap_err().to_string(),
183 "Attribute type EEokfxxqwAM08iku7VHMaVFBaEGYVi2W-ctBKaTW6QdJ doesn't exist"
184 );
185 }
186}