async_graphql/dynamic/
value_accessor.rs

1use std::borrow::Cow;
2
3use indexmap::IndexMap;
4use serde::de::DeserializeOwned;
5
6use crate::{Error, Name, Result, Upload, Value};
7
8/// A value accessor
9pub struct ValueAccessor<'a>(&'a Value);
10
11impl<'a> ValueAccessor<'a> {
12    /// Returns `true` if the value is null, otherwise returns `false`
13    #[inline]
14    pub fn is_null(&self) -> bool {
15        matches!(self.0, Value::Null)
16    }
17
18    /// Returns the boolean
19    pub fn boolean(&self) -> Result<bool> {
20        match self.0 {
21            Value::Boolean(b) => Ok(*b),
22            _ => Err(Error::new("internal: not a boolean")),
23        }
24    }
25
26    /// Returns the enum name
27    pub fn enum_name(&self) -> Result<&str> {
28        match self.0 {
29            Value::Enum(s) => Ok(s),
30            Value::String(s) => Ok(s.as_str()),
31            _ => Err(Error::new("internal: not an enum name")),
32        }
33    }
34
35    /// Returns the number as `i64`
36    pub fn i64(&self) -> Result<i64> {
37        if let Value::Number(number) = self.0 {
38            if let Some(value) = number.as_i64() {
39                return Ok(value);
40            }
41        }
42        Err(Error::new("internal: not an signed integer"))
43    }
44
45    /// Returns the number as `u64`
46    pub fn u64(&self) -> Result<u64> {
47        if let Value::Number(number) = self.0 {
48            if let Some(value) = number.as_u64() {
49                return Ok(value);
50            }
51        }
52        Err(Error::new("internal: not an unsigned integer"))
53    }
54
55    /// Returns the number as `f32`
56    pub fn f32(&self) -> Result<f32> {
57        if let Value::Number(number) = self.0 {
58            if let Some(value) = number.as_f64() {
59                return Ok(value as f32);
60            }
61        }
62        Err(Error::new("internal: not a float"))
63    }
64
65    /// Returns the number as `f64`
66    pub fn f64(&self) -> Result<f64> {
67        if let Value::Number(number) = self.0 {
68            if let Some(value) = number.as_f64() {
69                return Ok(value);
70            }
71        }
72        Err(Error::new("internal: not a float"))
73    }
74
75    /// Returns the string value
76    pub fn string(&self) -> Result<&'a str> {
77        if let Value::String(value) = self.0 {
78            Ok(value)
79        } else {
80            Err(Error::new("internal: not a string"))
81        }
82    }
83
84    /// Returns the object accessor
85    pub fn object(&self) -> Result<ObjectAccessor<'a>> {
86        if let Value::Object(obj) = self.0 {
87            Ok(ObjectAccessor(Cow::Borrowed(obj)))
88        } else {
89            Err(Error::new("internal: not an object"))
90        }
91    }
92
93    /// Returns the list accessor
94    pub fn list(&self) -> Result<ListAccessor<'a>> {
95        if let Value::List(list) = self.0 {
96            Ok(ListAccessor(list))
97        } else {
98            Err(Error::new("internal: not a list"))
99        }
100    }
101
102    /// Deserialize the value to `T`
103    pub fn deserialize<T: DeserializeOwned>(&self) -> Result<T> {
104        T::deserialize(self.0.clone()).map_err(|err| format!("internal: {}", err).into())
105    }
106
107    /// Returns a reference to the underlying `Value`
108    #[inline]
109    pub fn as_value(&self) -> &'a Value {
110        self.0
111    }
112
113    /// Returns a upload object
114    pub fn upload(&self) -> Result<Upload> {
115        <Upload as crate::InputType>::parse(Some(self.0.clone()))
116            .map_err(|_| Error::new("internal: not a upload"))
117    }
118}
119
120/// A object accessor
121pub struct ObjectAccessor<'a>(pub(crate) Cow<'a, IndexMap<Name, Value>>);
122
123impl<'a> ObjectAccessor<'a> {
124    /// Return a reference to the value stored for `key`, if it is present,
125    /// else `None`.
126    #[inline]
127    pub fn get(&self, name: &str) -> Option<ValueAccessor<'_>> {
128        self.0.get(name).map(ValueAccessor)
129    }
130
131    /// Like [`ObjectAccessor::get`], returns `Err` if the index does not exist
132    #[inline]
133    pub fn try_get(&self, name: &str) -> Result<ValueAccessor<'_>> {
134        self.0
135            .get(name)
136            .map(ValueAccessor)
137            .ok_or_else(|| Error::new(format!("internal: key \"{}\" not found", name)))
138    }
139
140    /// Return an iterator over the key-value pairs of the object, in their
141    /// order
142    #[inline]
143    pub fn iter(&self) -> impl Iterator<Item = (&Name, ValueAccessor<'_>)> + '_ {
144        self.0
145            .iter()
146            .map(|(name, value)| (name, ValueAccessor(value)))
147    }
148
149    /// Return an iterator over the keys of the object, in their order
150    #[inline]
151    pub fn keys(&self) -> impl Iterator<Item = &Name> + '_ {
152        self.0.keys()
153    }
154
155    /// Return an iterator over the values of the object, in their order
156    #[inline]
157    pub fn values(&self) -> impl Iterator<Item = ValueAccessor<'_>> + '_ {
158        self.0.values().map(ValueAccessor)
159    }
160
161    /// Returns the number of elements in the object
162    #[inline]
163    pub fn len(&self) -> usize {
164        self.0.len()
165    }
166
167    /// Returns `true` if the object has no members
168    #[must_use]
169    pub fn is_empty(&self) -> bool {
170        self.len() == 0
171    }
172
173    /// Returns a reference to the underlying IndexMap
174    #[inline]
175    pub fn as_index_map(&'a self) -> &'a IndexMap<Name, Value> {
176        &self.0
177    }
178}
179
180/// A list accessor
181pub struct ListAccessor<'a>(pub(crate) &'a [Value]);
182
183impl<'a> ListAccessor<'a> {
184    /// Returns the number of elements in the list
185    #[inline]
186    pub fn len(&self) -> usize {
187        self.0.len()
188    }
189
190    /// Returns `true` if the list has a length of 0
191    #[inline]
192    pub fn is_empty(&self) -> bool {
193        self.0.is_empty()
194    }
195
196    /// Returns an iterator over the list
197    #[inline]
198    pub fn iter(&self) -> impl Iterator<Item = ValueAccessor<'_>> + '_ {
199        self.0.iter().map(ValueAccessor)
200    }
201
202    /// Returns a reference to an element depending on the index
203    #[inline]
204    pub fn get(&self, idx: usize) -> Option<ValueAccessor<'_>> {
205        self.0.get(idx).map(ValueAccessor)
206    }
207
208    /// Like [`ListAccessor::get`], returns `Err` if the index does not exist
209    #[inline]
210    pub fn try_get(&self, idx: usize) -> Result<ValueAccessor<'_>> {
211        self.get(idx)
212            .ok_or_else(|| Error::new(format!("internal: index \"{}\" not found", idx)))
213    }
214
215    /// Returns a new ListAccessor that represents a slice of the original
216    #[inline]
217    pub fn as_slice(&self, start: usize, end: usize) -> Result<ListAccessor<'a>> {
218        if start <= end && end <= self.len() {
219            Ok(ListAccessor(&self.0[start..end]))
220        } else {
221            Err(Error::new("internal: invalid slice indices"))
222        }
223    }
224
225    /// Returns a reference to the underlying `&[Value]`
226    #[inline]
227    pub fn as_values_slice(&self) -> &'a [Value] {
228        self.0
229    }
230}