1use std::{borrow::Cow, collections::HashMap, num::NonZeroU64, sync::Arc};
2
3use rkyv::{collections::swiss_table::ArchivedHashMap, string::ArchivedString};
4use serde::{ser::SerializeMap, 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::{stable_object_hash, ArchivedRkyvValue, RkyvValue},
12 hashing,
13 interned_values::InternedStore,
14 log_e,
15};
16
17const TAG: &str = "DynamicReturnable";
18
19lazy_static::lazy_static! {
20 static ref EMPTY_DYNAMIC_RETURNABLE: DynamicReturnable = DynamicReturnable {
21 hash: 0,
22 value: DynamicReturnableValue::Null,
23 stable_hash: NonZeroU64::new(hashing::hash_u64_slice(&[0])),
24 };
25
26 static ref TRUE_DYNAMIC_RETURNABLE: DynamicReturnable = DynamicReturnable {
27 hash: 0,
28 value: DynamicReturnableValue::Bool(true),
29 stable_hash: NonZeroU64::new(hashing::hash_u64_slice(&[1, 1])),
30 };
31
32 static ref FALSE_DYNAMIC_RETURNABLE: DynamicReturnable = DynamicReturnable {
33 hash: 0,
34 value: DynamicReturnableValue::Bool(false),
35 stable_hash: NonZeroU64::new(hashing::hash_u64_slice(&[1, 0])),
36 };
37
38}
39
40#[derive(Clone, Debug)]
41pub struct DynamicReturnable {
42 pub hash: u64,
43 pub value: DynamicReturnableValue,
44 stable_hash: Option<NonZeroU64>,
45}
46
47impl DynamicReturnable {
48 pub fn empty() -> Self {
49 EMPTY_DYNAMIC_RETURNABLE.clone()
50 }
51
52 pub fn from_bool(value: bool) -> Self {
53 if value {
54 TRUE_DYNAMIC_RETURNABLE.clone()
55 } else {
56 FALSE_DYNAMIC_RETURNABLE.clone()
57 }
58 }
59
60 pub fn from_map(value: HashMap<String, JsonValue>) -> Self {
61 let raw_value = match to_raw_value(&value) {
62 Ok(raw_value) => raw_value,
63 Err(e) => {
64 log_e!(TAG, "Failed to convert map to raw value: {}", e);
65 return Self::empty();
66 }
67 };
68
69 InternedStore::get_or_intern_returnable(Cow::Owned(raw_value))
70 }
71
72 pub fn get_bool(&self) -> Option<bool> {
73 match self.value {
74 DynamicReturnableValue::Bool(value) => Some(value),
75 _ => None,
76 }
77 }
78
79 pub fn get_json_archived_ref(
80 &self,
81 ) -> Option<&'static ArchivedHashMap<ArchivedString, ArchivedRkyvValue>> {
82 match self.value {
83 DynamicReturnableValue::JsonArchived(v) => Some(v),
84 _ => None,
85 }
86 }
87
88 pub fn get_json_pointer_ref(&self) -> Option<&HashMap<String, RkyvValue>> {
89 match &self.value {
90 DynamicReturnableValue::JsonPointer(v) => Some(v.as_ref()),
91 DynamicReturnableValue::JsonStatic(v) => Some(v),
92 _ => None,
93 }
94 }
95
96 pub fn get_json(&self) -> Option<HashMap<String, JsonValue>> {
97 match &self.value {
98 DynamicReturnableValue::JsonPointer(v) => rkyv_hashmap_to_owned_json(v.as_ref()),
99 DynamicReturnableValue::JsonStatic(v) => rkyv_hashmap_to_owned_json(v),
100 DynamicReturnableValue::JsonArchived(v) => archived_hashmap_to_owned(v).map_or_else(
101 |e| {
102 log_e!(TAG, "Failed to convert archived json. Error: {}", e);
103 None
104 },
105 Some,
106 ),
107 _ => None,
108 }
109 }
110
111 pub fn get_hash(&self) -> u64 {
112 self.hash
113 }
114
115 pub(crate) fn get_stable_hash(&self) -> u64 {
116 if let Some(hash) = self.stable_hash {
117 return hash.get();
118 }
119
120 if matches!(&self.value, DynamicReturnableValue::JsonArchived(_)) {
121 if let Some(hash) = InternedStore::get_mmap_returnable_stable_hash(self.hash) {
122 return hash;
123 }
124 }
125
126 stable_hash(&self.value)
127 }
128
129 pub(crate) fn from_interned_value(hash: u64, value: DynamicReturnableValue) -> Self {
130 Self {
131 hash,
132 stable_hash: NonZeroU64::new(stable_hash(&value)),
133 value,
134 }
135 }
136
137 pub(crate) fn from_archived_value(
138 hash: u64,
139 value: &'static ArchivedHashMap<ArchivedString, ArchivedRkyvValue>,
140 ) -> Self {
141 Self {
142 hash,
143 value: DynamicReturnableValue::JsonArchived(value),
144 stable_hash: None,
145 }
146 }
147
148 #[cfg(test)]
149 pub(crate) fn has_inline_stable_hash(&self) -> bool {
150 self.stable_hash.is_some()
151 }
152}
153
154impl PartialEq for DynamicReturnable {
155 fn eq(&self, other: &Self) -> bool {
156 self.hash == other.hash && self.value == other.value
157 }
158}
159
160fn stable_hash(value: &DynamicReturnableValue) -> u64 {
161 match value {
162 DynamicReturnableValue::Null => hashing::hash_u64_slice(&[0]),
163 DynamicReturnableValue::Bool(value) => hashing::hash_u64_slice(&[1, u64::from(*value)]),
164 DynamicReturnableValue::JsonPointer(value) => {
165 stable_object_hash(value.iter().map(|(key, value)| (key.as_str(), value)))
166 }
167 DynamicReturnableValue::JsonStatic(value) => {
168 stable_object_hash(value.iter().map(|(key, value)| (key.as_str(), value)))
169 }
170 DynamicReturnableValue::JsonArchived(value) => archived_returnable_stable_hash(value),
171 }
172}
173
174pub(crate) fn archived_returnable_stable_hash(
175 value: &ArchivedHashMap<ArchivedString, ArchivedRkyvValue>,
176) -> u64 {
177 stable_object_hash(value.iter().map(|(key, value)| (key.as_str(), value)))
178}
179
180impl<'de> Deserialize<'de> for DynamicReturnable {
181 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
182 where
183 D: Deserializer<'de>,
184 {
185 let raw_value_ref: Cow<RawValue> = Deserialize::deserialize(deserializer)?;
186 Ok(InternedStore::get_or_intern_returnable(raw_value_ref))
187 }
188}
189
190impl Serialize for DynamicReturnable {
191 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
192 where
193 S: Serializer,
194 {
195 match &self.value {
196 DynamicReturnableValue::JsonPointer(raw) => raw.serialize(serializer),
197 DynamicReturnableValue::JsonStatic(raw) => raw.serialize(serializer),
198 DynamicReturnableValue::JsonArchived(raw) => {
199 let mut map = serializer.serialize_map(Some(raw.len()))?;
200 for (key, value) in raw.iter() {
201 map.serialize_entry(key.as_str(), value)?;
202 }
203 map.end()
204 }
205 DynamicReturnableValue::Null => serializer.serialize_none(),
206 DynamicReturnableValue::Bool(value) => serializer.serialize_bool(*value),
207 }
208 }
209}
210
211#[derive(Clone, Debug)]
214pub enum DynamicReturnableValue {
215 Null,
216 Bool(bool),
217 JsonPointer(Arc<HashMap<String, RkyvValue>>),
218 JsonStatic(&'static HashMap<String, RkyvValue>),
219 JsonArchived(&'static ArchivedHashMap<ArchivedString, ArchivedRkyvValue>),
220}
221
222impl PartialEq for DynamicReturnableValue {
223 fn eq(&self, other: &Self) -> bool {
224 match (self, other) {
225 (DynamicReturnableValue::Null, DynamicReturnableValue::Null) => return true,
226 (DynamicReturnableValue::Bool(a), DynamicReturnableValue::Bool(b)) => return *a == *b,
227 _ => {}
228 };
229
230 if let DynamicReturnableValue::JsonPointer(a) = self {
231 match other {
232 DynamicReturnableValue::JsonPointer(b) => return a.as_ref() == b.as_ref(),
233 DynamicReturnableValue::JsonStatic(b) => return a.as_ref() == *b,
234 DynamicReturnableValue::JsonArchived(b) => return eq_check(b, a.as_ref()),
235 _ => return false,
236 }
237 }
238
239 if let DynamicReturnableValue::JsonStatic(a) = self {
240 match other {
241 DynamicReturnableValue::JsonPointer(b) => return *a == b.as_ref(),
242 DynamicReturnableValue::JsonStatic(b) => return a == b,
243 DynamicReturnableValue::JsonArchived(b) => return eq_check(b, a),
244 _ => return false,
245 }
246 }
247
248 if let DynamicReturnableValue::JsonArchived(a) = self {
249 match other {
250 DynamicReturnableValue::JsonPointer(b) => return eq_check(a, b.as_ref()),
251 DynamicReturnableValue::JsonStatic(b) => return eq_check(a, b),
252 DynamicReturnableValue::JsonArchived(b) => return a == b,
253 _ => return false,
254 }
255 }
256
257 false
258 }
259}
260
261fn eq_check(
264 left: &ArchivedHashMap<ArchivedString, ArchivedRkyvValue>,
265 right: &HashMap<String, RkyvValue>,
266) -> bool {
267 for (key, value) in left.iter() {
268 match right.get_key_value(key.as_str()) {
269 Some((left_key, left_value)) => {
270 if left_key != key {
271 return false;
272 }
273 if left_value != value {
274 return false;
275 }
276 }
277 None => return false,
278 };
279 }
280 true
281}
282
283fn rkyv_hashmap_to_owned_json(
284 raw: &HashMap<String, RkyvValue>,
285) -> Option<HashMap<String, JsonValue>> {
286 match serde_json::to_value(raw) {
287 Ok(JsonValue::Object(o)) => Some(o.into_iter().collect()),
288 Ok(_) => None,
289 Err(e) => {
290 log_e!(TAG, "Failed to convert json. Error: {}", e);
291 None
292 }
293 }
294}
295
296fn archived_hashmap_to_owned(
297 raw: &'static ArchivedHashMap<ArchivedString, ArchivedRkyvValue>,
298) -> Result<HashMap<String, JsonValue>, serde_json::Error> {
299 let mut taken: HashMap<String, JsonValue> = HashMap::new();
300 for (key, value) in raw.iter() {
301 taken.insert(key.as_str().to_string(), serde_json::to_value(value)?);
302 }
303
304 Ok(taken)
305}