Skip to main content

hive_router_plan_executor/response/
value.rs

1use core::fmt;
2use hive_router_query_planner::ast::selection_item::SelectionItem;
3use serde::{
4    de::{self, Deserializer, MapAccess, SeqAccess, Visitor},
5    ser::{SerializeMap, SerializeSeq},
6};
7use sonic_rs::{JsonNumberTrait, ValueRef};
8use std::{
9    borrow::Cow,
10    fmt::Display,
11    hash::{Hash, Hasher},
12};
13use xxhash_rust::xxh3::Xxh3;
14
15use crate::{introspection::schema::PossibleTypes, utils::consts::TYPENAME_FIELD_NAME};
16
17#[derive(Debug, Clone, Default)]
18pub enum Value<'a> {
19    #[default]
20    Null,
21    F64(f64),
22    I64(i64),
23    U64(u64),
24    Bool(bool),
25    String(Cow<'a, str>),
26    Array(Vec<Value<'a>>),
27    Object(Vec<(&'a str, Value<'a>)>),
28}
29
30impl Hash for Value<'_> {
31    fn hash<H: Hasher>(&self, state: &mut H) {
32        match self {
33            Value::Null => 0.hash(state),
34            Value::F64(f) => f.to_bits().hash(state),
35            Value::I64(i) => i.hash(state),
36            Value::U64(u) => u.hash(state),
37            Value::Bool(b) => b.hash(state),
38            Value::String(s) => s.hash(state),
39            Value::Array(arr) => arr.hash(state),
40            Value::Object(obj) => obj.hash(state),
41        }
42    }
43}
44
45impl<'a> Value<'a> {
46    pub fn take_entities(&mut self) -> Option<Vec<Value<'a>>> {
47        match self {
48            Value::Object(data) => {
49                if let Ok(entities_idx) = data.binary_search_by_key(&"_entities", |(k, _)| *k) {
50                    if let Value::Array(arr) = data.remove(entities_idx).1 {
51                        return Some(arr);
52                    }
53                }
54                None
55            }
56            _ => None,
57        }
58    }
59
60    pub fn to_hash(
61        &self,
62        selection_items: &[SelectionItem],
63        possible_types: &PossibleTypes,
64    ) -> u64 {
65        let mut hasher = Xxh3::new();
66        self.hash_with_requires(&mut hasher, selection_items, possible_types);
67        hasher.finish()
68    }
69
70    fn hash_with_requires<H: Hasher>(
71        &self,
72        state: &mut H,
73        selection_items: &[SelectionItem],
74        possible_types: &PossibleTypes,
75    ) {
76        if selection_items.is_empty() {
77            self.hash(state);
78            return;
79        }
80
81        match self {
82            Value::Object(obj) => {
83                Value::hash_object_with_requires(state, obj, selection_items, possible_types);
84            }
85            Value::Array(arr) => {
86                for item in arr {
87                    item.hash_with_requires(state, selection_items, possible_types);
88                }
89            }
90            _ => {
91                self.hash(state);
92            }
93        }
94    }
95
96    fn hash_object_with_requires<H: Hasher>(
97        state: &mut H,
98        obj: &[(&'a str, Value<'a>)],
99        selection_items: &[SelectionItem],
100        possible_types: &PossibleTypes,
101    ) {
102        for item in selection_items {
103            match item {
104                SelectionItem::Field(field_selection) => {
105                    let field_name = &field_selection.name;
106                    if let Ok(idx) = obj.binary_search_by_key(&field_name.as_str(), |(k, _)| k) {
107                        let (key, value) = &obj[idx];
108                        key.hash(state);
109                        value.hash_with_requires(
110                            state,
111                            &field_selection.selections.items,
112                            possible_types,
113                        );
114                    }
115                }
116                SelectionItem::InlineFragment(inline_fragment) => {
117                    let type_condition = &inline_fragment.type_condition;
118                    let type_name = obj
119                        .binary_search_by_key(&TYPENAME_FIELD_NAME, |(k, _)| k)
120                        .ok()
121                        .and_then(|idx| obj[idx].1.as_str())
122                        .unwrap_or(type_condition);
123
124                    if possible_types.entity_satisfies_type_condition(type_name, type_condition) {
125                        Value::hash_object_with_requires(
126                            state,
127                            obj,
128                            &inline_fragment.selections.items,
129                            possible_types,
130                        );
131                    }
132                }
133                SelectionItem::FragmentSpread(_) => {
134                    unreachable!("Fragment spreads should not exist in FetchNode::requires.")
135                }
136            }
137        }
138    }
139
140    pub fn from(json: ValueRef<'a>) -> Value<'a> {
141        match json {
142            ValueRef::Null => Value::Null,
143            ValueRef::Bool(b) => Value::Bool(b),
144            ValueRef::String(s) => Value::String(s.into()),
145            ValueRef::Number(num) => {
146                if let Some(num) = num.as_u64() {
147                    return Value::U64(num);
148                }
149
150                if let Some(num) = num.as_i64() {
151                    return Value::I64(num);
152                }
153
154                // All integers are floats, so to prevent to add
155                // extra dots for integer numbers, we check for f64 last.
156                if let Some(num) = num.as_f64() {
157                    return Value::F64(num);
158                }
159
160                Value::Null
161            }
162            ValueRef::Array(arr) => {
163                let mut vec = Vec::with_capacity(arr.len());
164                vec.extend(arr.iter().map(|v| Value::from(v.as_ref())));
165                Value::Array(vec)
166            }
167            ValueRef::Object(obj) => {
168                let mut vec = Vec::with_capacity(obj.len());
169                vec.extend(obj.iter().map(|(k, v)| (k, Value::from(v.as_ref()))));
170                vec.sort_unstable_by_key(|(k, _)| *k);
171                Value::Object(vec)
172            }
173        }
174    }
175
176    pub fn as_object(&self) -> Option<&Vec<(&'a str, Value<'a>)>> {
177        match self {
178            Value::Object(obj) => Some(obj),
179            _ => None,
180        }
181    }
182
183    pub fn as_str(&self) -> Option<&str> {
184        match self {
185            Value::String(s) => Some(s),
186            _ => None,
187        }
188    }
189
190    pub fn is_null(&self) -> bool {
191        matches!(self, Value::Null)
192    }
193
194    pub fn is_object(&self) -> bool {
195        matches!(self, Value::Object(_))
196    }
197}
198
199// Our new trait with the desired methods
200pub trait ValueRefExt {
201    fn to_data<'a>(&'a self) -> Option<ValueRef<'a>>;
202    fn to_entities<'a>(&'a self) -> Option<Vec<ValueRef<'a>>>;
203}
204
205// Implement our trait for the foreign type
206impl ValueRefExt for ValueRef<'_> {
207    fn to_data<'a>(&'a self) -> Option<ValueRef<'a>> {
208        match self {
209            ValueRef::Object(obj) => obj.get(&"data").map(|v| v.as_ref()),
210            _ => None,
211        }
212    }
213
214    fn to_entities<'a>(&'a self) -> Option<Vec<ValueRef<'a>>> {
215        match self.to_data().unwrap() {
216            ValueRef::Object(obj) => obj.get(&"_entities").and_then(|v| match v.as_ref() {
217                ValueRef::Array(arr) => Some(arr.iter().map(|v| v.as_ref()).collect()),
218                _ => None,
219            }),
220            _ => None,
221        }
222    }
223}
224
225impl Display for Value<'_> {
226    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227        match self {
228            Value::Null => write!(f, "null"),
229            Value::Bool(b) => write!(f, "{}", b),
230            Value::String(s) => write!(f, "\"{}\"", s),
231            Value::F64(n) => write!(f, "{}", n),
232            Value::U64(n) => write!(f, "{}", n),
233            Value::I64(n) => write!(f, "{}", n),
234            Value::Array(arr) => {
235                write!(f, "[")?;
236                for (i, v) in arr.iter().enumerate() {
237                    if i > 0 {
238                        write!(f, ", ")?;
239                    }
240                    write!(f, "{}", v)?;
241                }
242                write!(f, "]")
243            }
244            Value::Object(obj) => {
245                write!(f, "{{")?;
246                for (i, (k, v)) in obj.iter().enumerate() {
247                    if i > 0 {
248                        write!(f, ", ")?;
249                    }
250                    write!(f, "\"{}\": {}", k, v)?;
251                }
252                write!(f, "}}")
253            }
254        }
255    }
256}
257
258struct ValueVisitor<'a> {
259    // We need a marker to hold the lifetime 'a.
260    _marker: std::marker::PhantomData<&'a ()>,
261}
262
263impl<'de> de::Deserialize<'de> for Value<'de> {
264    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
265    where
266        D: Deserializer<'de>,
267    {
268        deserializer.deserialize_any(ValueVisitor {
269            _marker: std::marker::PhantomData,
270        })
271    }
272}
273
274impl<'de> Visitor<'de> for ValueVisitor<'de> {
275    type Value = Value<'de>;
276
277    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
278        formatter.write_str("any valid JSON value")
279    }
280
281    fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E> {
282        Ok(Value::Bool(value))
283    }
284
285    fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
286        Ok(Value::I64(value))
287    }
288
289    fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
290        Ok(Value::U64(value))
291    }
292
293    fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> {
294        Ok(Value::F64(value))
295    }
296
297    // This is the zero-copy part. We borrow the string slice directly from the input.
298    fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E>
299    where
300        E: de::Error,
301    {
302        Ok(Value::String(value.into()))
303    }
304
305    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
306    where
307        E: de::Error,
308    {
309        Ok(Value::String(v.to_owned().into()))
310    }
311
312    fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
313    where
314        E: de::Error,
315    {
316        Ok(Value::String(value.into()))
317    }
318
319    fn visit_unit<E>(self) -> Result<Self::Value, E> {
320        Ok(Value::Null)
321    }
322
323    // For arrays, Serde recursively calls `deserialize` for the inner type.
324    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
325    where
326        A: SeqAccess<'de>,
327    {
328        let mut elements = Vec::with_capacity(seq.size_hint().unwrap_or(0));
329        while let Some(elem) = seq.next_element()? {
330            elements.push(elem);
331        }
332        Ok(Value::Array(elements))
333    }
334
335    // For objects, the same happens for keys and values.
336    fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
337    where
338        M: MapAccess<'de>,
339    {
340        let mut entries = Vec::with_capacity(map.size_hint().unwrap_or(0));
341        while let Some((key, value)) = map.next_entry()? {
342            entries.push((key, value));
343        }
344        // IMPORTANT: We keep the sort for binary search compatibility.
345        entries.sort_unstable_by_key(|(k, _)| *k);
346        Ok(Value::Object(entries))
347    }
348}
349
350impl serde::Serialize for Value<'_> {
351    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
352    where
353        S: serde::Serializer,
354    {
355        match self {
356            Value::Null => serializer.serialize_unit(),
357            Value::Bool(b) => serializer.serialize_bool(*b),
358            Value::I64(n) => serializer.serialize_i64(*n),
359            Value::U64(n) => serializer.serialize_u64(*n),
360            Value::F64(n) => serializer.serialize_f64(*n),
361            Value::String(s) => serializer.serialize_str(s),
362            Value::Array(arr) => {
363                let mut seq = serializer.serialize_seq(Some(arr.len()))?;
364                for v in arr {
365                    seq.serialize_element(v)?;
366                }
367                seq.end()
368            }
369            Value::Object(obj) => {
370                let mut map = serializer.serialize_map(Some(obj.len()))?;
371                for (k, v) in obj {
372                    map.serialize_entry(k, v)?;
373                }
374                map.end()
375            }
376        }
377    }
378}
379
380#[cfg(test)]
381mod tests {
382    use super::Value;
383    use serde::Deserialize;
384    use std::borrow::Cow;
385
386    #[test]
387    fn deserializes_escaped_string_as_owned() {
388        let bytes = br#"{"message": "hello\nworld"}"#;
389        let mut deserializer = sonic_rs::Deserializer::from_slice(bytes);
390
391        let value = Value::deserialize(&mut deserializer).unwrap();
392
393        let obj = match value {
394            Value::Object(obj) => obj,
395            _ => panic!("Expected Value::Object"),
396        };
397
398        let message_value = &obj.iter().find(|(k, _)| *k == "message").unwrap().1;
399
400        match message_value {
401            Value::String(value) => {
402                assert_eq!(value, "hello\nworld");
403                assert!(
404                    matches!(value, Cow::Owned(_)),
405                    "Expected Cow::Owned for escaped string"
406                );
407            }
408            _ => panic!("Expected Value::String"),
409        }
410    }
411
412    #[test]
413    fn deserializes_simple_string_as_borrowed() {
414        let bytes = br#"{"message": "hello world"}"#;
415        let mut deserializer = sonic_rs::Deserializer::from_slice(bytes);
416        let value = Value::deserialize(&mut deserializer).unwrap();
417
418        let obj = match value {
419            Value::Object(obj) => obj,
420            _ => panic!("Expected Value::Object"),
421        };
422
423        let message_value = &obj.iter().find(|(k, _)| *k == "message").unwrap().1;
424
425        match message_value {
426            Value::String(value) => {
427                assert_eq!(value, "hello world");
428                assert!(
429                    matches!(value, Cow::Borrowed(_)),
430                    "Expected Cow::Borrowed for simple string"
431                );
432            }
433            _ => panic!("Expected Value::String"),
434        }
435    }
436}