1use std::{borrow::Cow, collections::HashMap, sync::Arc};
2
3use rkyv::{collections::swiss_table::ArchivedHashMap, string::ArchivedString};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_json::{
6 value::{to_raw_value, RawValue},
7 Value as JsonValue,
8};
9
10use crate::{
11 evaluation::rkyv_value::{ArchivedRkyvValue, RkyvValue},
12 interned_values::InternedStore,
13 log_e,
14};
15
16const TAG: &str = "DynamicReturnable";
17
18lazy_static::lazy_static! {
19 static ref EMPTY_DYNAMIC_RETURNABLE: DynamicReturnable = DynamicReturnable {
20 hash: 0,
21 value: DynamicReturnableValue::Null,
22 };
23
24 static ref TRUE_DYNAMIC_RETURNABLE: DynamicReturnable = DynamicReturnable {
25 hash: 0,
26 value: DynamicReturnableValue::Bool(true),
27 };
28
29 static ref FALSE_DYNAMIC_RETURNABLE: DynamicReturnable = DynamicReturnable {
30 hash: 0,
31 value: DynamicReturnableValue::Bool(false),
32 };
33
34}
35
36#[derive(Clone, PartialEq, Debug)]
37pub struct DynamicReturnable {
38 pub hash: u64,
39 pub value: DynamicReturnableValue,
40}
41
42impl DynamicReturnable {
43 pub fn empty() -> Self {
44 EMPTY_DYNAMIC_RETURNABLE.clone()
45 }
46
47 pub fn from_bool(value: bool) -> Self {
48 if value {
49 TRUE_DYNAMIC_RETURNABLE.clone()
50 } else {
51 FALSE_DYNAMIC_RETURNABLE.clone()
52 }
53 }
54
55 pub fn from_map(value: HashMap<String, JsonValue>) -> Self {
56 let raw_value = match to_raw_value(&value) {
57 Ok(raw_value) => raw_value,
58 Err(e) => {
59 log_e!(TAG, "Failed to convert map to raw value: {}", e);
60 return Self::empty();
61 }
62 };
63
64 InternedStore::get_or_intern_returnable(Cow::Owned(raw_value))
65 }
66
67 pub fn get_bool(&self) -> Option<bool> {
68 match self.value {
69 DynamicReturnableValue::Bool(value) => Some(value),
70 _ => None,
71 }
72 }
73
74 pub fn get_json_archived_ref(
75 &self,
76 ) -> Option<&'static ArchivedHashMap<ArchivedString, ArchivedRkyvValue>> {
77 match self.value {
78 DynamicReturnableValue::JsonArchived(v) => Some(v),
79 _ => None,
80 }
81 }
82
83 pub fn get_json_pointer_ref(&self) -> Option<&HashMap<String, RkyvValue>> {
84 match &self.value {
85 DynamicReturnableValue::JsonPointer(v) => Some(v.as_ref()),
86 DynamicReturnableValue::JsonStatic(v) => Some(v),
87 _ => None,
88 }
89 }
90
91 pub fn get_json(&self) -> Option<HashMap<String, JsonValue>> {
92 match &self.value {
93 DynamicReturnableValue::JsonPointer(v) => rkyv_hashmap_to_owned_json(v.as_ref()),
94 DynamicReturnableValue::JsonStatic(v) => rkyv_hashmap_to_owned_json(v),
95 DynamicReturnableValue::JsonArchived(v) => archived_hashmap_to_owned(v).map_or_else(
96 |e| {
97 log_e!(TAG, "Failed to convert archived json. Error: {}", e);
98 None
99 },
100 Some,
101 ),
102 _ => None,
103 }
104 }
105
106 pub fn get_hash(&self) -> u64 {
107 self.hash
108 }
109}
110
111impl<'de> Deserialize<'de> for DynamicReturnable {
112 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
113 where
114 D: Deserializer<'de>,
115 {
116 let raw_value_ref: Cow<RawValue> = Deserialize::deserialize(deserializer)?;
117 Ok(InternedStore::get_or_intern_returnable(raw_value_ref))
118 }
119}
120
121impl Serialize for DynamicReturnable {
122 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
123 where
124 S: Serializer,
125 {
126 match &self.value {
127 DynamicReturnableValue::JsonPointer(raw) => raw.serialize(serializer),
128 DynamicReturnableValue::JsonStatic(raw) => raw.serialize(serializer),
129 DynamicReturnableValue::JsonArchived(raw) => {
130 let owned = archived_hashmap_to_owned(raw).map_err(serde::ser::Error::custom)?;
131 owned.serialize(serializer)
132 }
133 DynamicReturnableValue::Null => serializer.serialize_none(),
134 DynamicReturnableValue::Bool(value) => serializer.serialize_bool(*value),
135 }
136 }
137}
138
139impl Drop for DynamicReturnable {
140 fn drop(&mut self) {
141 self.value = DynamicReturnableValue::Null;
142 InternedStore::release_returnable(self.hash);
143 }
144}
145
146#[derive(Clone, Debug)]
149pub enum DynamicReturnableValue {
150 Null,
151 Bool(bool),
152 JsonPointer(Arc<HashMap<String, RkyvValue>>),
153 JsonStatic(&'static HashMap<String, RkyvValue>),
154 JsonArchived(&'static ArchivedHashMap<ArchivedString, ArchivedRkyvValue>),
155}
156
157impl PartialEq for DynamicReturnableValue {
158 fn eq(&self, other: &Self) -> bool {
159 match (self, other) {
160 (DynamicReturnableValue::Null, DynamicReturnableValue::Null) => return true,
161 (DynamicReturnableValue::Bool(a), DynamicReturnableValue::Bool(b)) => return *a == *b,
162 _ => {}
163 };
164
165 if let DynamicReturnableValue::JsonPointer(a) = self {
166 match other {
167 DynamicReturnableValue::JsonPointer(b) => return a.as_ref() == b.as_ref(),
168 DynamicReturnableValue::JsonStatic(b) => return a.as_ref() == *b,
169 DynamicReturnableValue::JsonArchived(b) => return eq_check(b, a.as_ref()),
170 _ => return false,
171 }
172 }
173
174 if let DynamicReturnableValue::JsonStatic(a) = self {
175 match other {
176 DynamicReturnableValue::JsonPointer(b) => return *a == b.as_ref(),
177 DynamicReturnableValue::JsonStatic(b) => return a == b,
178 DynamicReturnableValue::JsonArchived(b) => return eq_check(b, a),
179 _ => return false,
180 }
181 }
182
183 if let DynamicReturnableValue::JsonArchived(a) = self {
184 match other {
185 DynamicReturnableValue::JsonPointer(b) => return eq_check(a, b.as_ref()),
186 DynamicReturnableValue::JsonStatic(b) => return eq_check(a, b),
187 DynamicReturnableValue::JsonArchived(b) => return a == b,
188 _ => return false,
189 }
190 }
191
192 false
193 }
194}
195
196fn eq_check(
199 left: &ArchivedHashMap<ArchivedString, ArchivedRkyvValue>,
200 right: &HashMap<String, RkyvValue>,
201) -> bool {
202 for (key, value) in left.iter() {
203 match right.get_key_value(key.as_str()) {
204 Some((left_key, left_value)) => {
205 if left_key != key {
206 return false;
207 }
208 if left_value != value {
209 return false;
210 }
211 }
212 None => return false,
213 };
214 }
215 true
216}
217
218fn rkyv_hashmap_to_owned_json(
219 raw: &HashMap<String, RkyvValue>,
220) -> Option<HashMap<String, JsonValue>> {
221 match serde_json::to_value(raw) {
222 Ok(JsonValue::Object(o)) => Some(o.into_iter().collect()),
223 Ok(_) => None,
224 Err(e) => {
225 log_e!(TAG, "Failed to convert json. Error: {}", e);
226 None
227 }
228 }
229}
230
231fn archived_hashmap_to_owned(
232 raw: &'static ArchivedHashMap<ArchivedString, ArchivedRkyvValue>,
233) -> Result<HashMap<String, JsonValue>, serde_json::Error> {
234 let mut taken: HashMap<String, JsonValue> = HashMap::new();
235 for (key, value) in raw.iter() {
236 taken.insert(key.as_str().to_string(), serde_json::to_value(value)?);
237 }
238
239 Ok(taken)
240}