async_graphql/dynamic/
value_accessor.rs1use std::borrow::Cow;
2
3use indexmap::IndexMap;
4use serde::de::DeserializeOwned;
5
6use crate::{Error, Name, Result, Upload, Value};
7
8pub struct ValueAccessor<'a>(&'a Value);
10
11impl<'a> ValueAccessor<'a> {
12 #[inline]
14 pub fn is_null(&self) -> bool {
15 matches!(self.0, Value::Null)
16 }
17
18 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 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 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 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 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 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 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 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 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 pub fn deserialize<T: DeserializeOwned>(&self) -> Result<T> {
104 T::deserialize(self.0.clone()).map_err(|err| format!("internal: {}", err).into())
105 }
106
107 #[inline]
109 pub fn as_value(&self) -> &'a Value {
110 self.0
111 }
112
113 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
120pub struct ObjectAccessor<'a>(pub(crate) Cow<'a, IndexMap<Name, Value>>);
122
123impl<'a> ObjectAccessor<'a> {
124 #[inline]
127 pub fn get(&self, name: &str) -> Option<ValueAccessor<'_>> {
128 self.0.get(name).map(ValueAccessor)
129 }
130
131 #[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 #[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 #[inline]
151 pub fn keys(&self) -> impl Iterator<Item = &Name> + '_ {
152 self.0.keys()
153 }
154
155 #[inline]
157 pub fn values(&self) -> impl Iterator<Item = ValueAccessor<'_>> + '_ {
158 self.0.values().map(ValueAccessor)
159 }
160
161 #[inline]
163 pub fn len(&self) -> usize {
164 self.0.len()
165 }
166
167 #[must_use]
169 pub fn is_empty(&self) -> bool {
170 self.len() == 0
171 }
172
173 #[inline]
175 pub fn as_index_map(&'a self) -> &'a IndexMap<Name, Value> {
176 &self.0
177 }
178}
179
180pub struct ListAccessor<'a>(pub(crate) &'a [Value]);
182
183impl<'a> ListAccessor<'a> {
184 #[inline]
186 pub fn len(&self) -> usize {
187 self.0.len()
188 }
189
190 #[inline]
192 pub fn is_empty(&self) -> bool {
193 self.0.is_empty()
194 }
195
196 #[inline]
198 pub fn iter(&self) -> impl Iterator<Item = ValueAccessor<'_>> + '_ {
199 self.0.iter().map(ValueAccessor)
200 }
201
202 #[inline]
204 pub fn get(&self, idx: usize) -> Option<ValueAccessor<'_>> {
205 self.0.get(idx).map(ValueAccessor)
206 }
207
208 #[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 #[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 #[inline]
227 pub fn as_values_slice(&self) -> &'a [Value] {
228 self.0
229 }
230}