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 self.stable_hash
117 .map_or_else(|| stable_hash(&self.value), NonZeroU64::get)
118 }
119
120 pub(crate) fn from_interned_value(hash: u64, value: DynamicReturnableValue) -> Self {
121 Self {
122 hash,
123 stable_hash: NonZeroU64::new(stable_hash(&value)),
124 value,
125 }
126 }
127
128 pub(crate) fn from_archived_value(
129 hash: u64,
130 value: &'static ArchivedHashMap<ArchivedString, ArchivedRkyvValue>,
131 ) -> Self {
132 Self {
133 hash,
134 value: DynamicReturnableValue::JsonArchived(value),
135 stable_hash: None,
136 }
137 }
138
139 #[cfg(test)]
140 pub(crate) fn has_precomputed_stable_hash(&self) -> bool {
141 self.stable_hash.is_some()
142 }
143}
144
145impl PartialEq for DynamicReturnable {
146 fn eq(&self, other: &Self) -> bool {
147 self.hash == other.hash && self.value == other.value
148 }
149}
150
151fn stable_hash(value: &DynamicReturnableValue) -> u64 {
152 match value {
153 DynamicReturnableValue::Null => hashing::hash_u64_slice(&[0]),
154 DynamicReturnableValue::Bool(value) => hashing::hash_u64_slice(&[1, u64::from(*value)]),
155 DynamicReturnableValue::JsonPointer(value) => {
156 stable_object_hash(value.iter().map(|(key, value)| (key.as_str(), value)))
157 }
158 DynamicReturnableValue::JsonStatic(value) => {
159 stable_object_hash(value.iter().map(|(key, value)| (key.as_str(), value)))
160 }
161 DynamicReturnableValue::JsonArchived(value) => {
162 stable_object_hash(value.iter().map(|(key, value)| (key.as_str(), value)))
163 }
164 }
165}
166
167impl<'de> Deserialize<'de> for DynamicReturnable {
168 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
169 where
170 D: Deserializer<'de>,
171 {
172 let raw_value_ref: Cow<RawValue> = Deserialize::deserialize(deserializer)?;
173 Ok(InternedStore::get_or_intern_returnable(raw_value_ref))
174 }
175}
176
177impl Serialize for DynamicReturnable {
178 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
179 where
180 S: Serializer,
181 {
182 match &self.value {
183 DynamicReturnableValue::JsonPointer(raw) => raw.serialize(serializer),
184 DynamicReturnableValue::JsonStatic(raw) => raw.serialize(serializer),
185 DynamicReturnableValue::JsonArchived(raw) => {
186 let mut map = serializer.serialize_map(Some(raw.len()))?;
187 for (key, value) in raw.iter() {
188 map.serialize_entry(key.as_str(), value)?;
189 }
190 map.end()
191 }
192 DynamicReturnableValue::Null => serializer.serialize_none(),
193 DynamicReturnableValue::Bool(value) => serializer.serialize_bool(*value),
194 }
195 }
196}
197
198#[derive(Clone, Debug)]
201pub enum DynamicReturnableValue {
202 Null,
203 Bool(bool),
204 JsonPointer(Arc<HashMap<String, RkyvValue>>),
205 JsonStatic(&'static HashMap<String, RkyvValue>),
206 JsonArchived(&'static ArchivedHashMap<ArchivedString, ArchivedRkyvValue>),
207}
208
209impl PartialEq for DynamicReturnableValue {
210 fn eq(&self, other: &Self) -> bool {
211 match (self, other) {
212 (DynamicReturnableValue::Null, DynamicReturnableValue::Null) => return true,
213 (DynamicReturnableValue::Bool(a), DynamicReturnableValue::Bool(b)) => return *a == *b,
214 _ => {}
215 };
216
217 if let DynamicReturnableValue::JsonPointer(a) = self {
218 match other {
219 DynamicReturnableValue::JsonPointer(b) => return a.as_ref() == b.as_ref(),
220 DynamicReturnableValue::JsonStatic(b) => return a.as_ref() == *b,
221 DynamicReturnableValue::JsonArchived(b) => return eq_check(b, a.as_ref()),
222 _ => return false,
223 }
224 }
225
226 if let DynamicReturnableValue::JsonStatic(a) = self {
227 match other {
228 DynamicReturnableValue::JsonPointer(b) => return *a == b.as_ref(),
229 DynamicReturnableValue::JsonStatic(b) => return a == b,
230 DynamicReturnableValue::JsonArchived(b) => return eq_check(b, a),
231 _ => return false,
232 }
233 }
234
235 if let DynamicReturnableValue::JsonArchived(a) = self {
236 match other {
237 DynamicReturnableValue::JsonPointer(b) => return eq_check(a, b.as_ref()),
238 DynamicReturnableValue::JsonStatic(b) => return eq_check(a, b),
239 DynamicReturnableValue::JsonArchived(b) => return a == b,
240 _ => return false,
241 }
242 }
243
244 false
245 }
246}
247
248fn eq_check(
251 left: &ArchivedHashMap<ArchivedString, ArchivedRkyvValue>,
252 right: &HashMap<String, RkyvValue>,
253) -> bool {
254 for (key, value) in left.iter() {
255 match right.get_key_value(key.as_str()) {
256 Some((left_key, left_value)) => {
257 if left_key != key {
258 return false;
259 }
260 if left_value != value {
261 return false;
262 }
263 }
264 None => return false,
265 };
266 }
267 true
268}
269
270fn rkyv_hashmap_to_owned_json(
271 raw: &HashMap<String, RkyvValue>,
272) -> Option<HashMap<String, JsonValue>> {
273 match serde_json::to_value(raw) {
274 Ok(JsonValue::Object(o)) => Some(o.into_iter().collect()),
275 Ok(_) => None,
276 Err(e) => {
277 log_e!(TAG, "Failed to convert json. Error: {}", e);
278 None
279 }
280 }
281}
282
283fn archived_hashmap_to_owned(
284 raw: &'static ArchivedHashMap<ArchivedString, ArchivedRkyvValue>,
285) -> Result<HashMap<String, JsonValue>, serde_json::Error> {
286 let mut taken: HashMap<String, JsonValue> = HashMap::new();
287 for (key, value) in raw.iter() {
288 taken.insert(key.as_str().to_string(), serde_json::to_value(value)?);
289 }
290
291 Ok(taken)
292}