cynic_parser/values/
const_value.rs

1use crate::{AstLookup, Span};
2
3use super::{
4    const_lists::ConstList,
5    const_objects::ConstObject,
6    enums::EnumValue,
7    iter::{Iter, ValueStoreReader},
8    scalars::{BooleanValue, FloatValue, IntValue, NullValue, StringValue},
9    value::ValueKind,
10    ConstObjectField, ConstValueId, Cursor, Value, ValueId,
11};
12
13#[derive(Debug, Copy, Clone)]
14pub enum ConstValue<'a> {
15    Int(IntValue<'a>),
16    Float(FloatValue<'a>),
17    String(StringValue<'a>),
18    Boolean(BooleanValue<'a>),
19    Null(NullValue<'a>),
20    Enum(EnumValue<'a>),
21    List(ConstList<'a>),
22    Object(ConstObject<'a>),
23}
24
25impl ConstValue<'_> {
26    pub fn span(&self) -> Span {
27        match self {
28            ConstValue::Int(inner) => inner.span(),
29            ConstValue::Float(inner) => inner.span(),
30            ConstValue::String(inner) => inner.span(),
31            ConstValue::Boolean(inner) => inner.span(),
32            ConstValue::Null(inner) => inner.span(),
33            ConstValue::Enum(inner) => inner.span(),
34            ConstValue::List(inner) => inner.span(),
35            ConstValue::Object(inner) => inner.span(),
36        }
37    }
38}
39
40impl<'a> ConstValue<'a> {
41    pub fn is_int(&self) -> bool {
42        matches!(self, Self::Int(_))
43    }
44
45    pub fn as_i32(&self) -> Option<i32> {
46        match self {
47            Self::Int(inner) => Some(inner.as_i32()),
48            _ => None,
49        }
50    }
51
52    pub fn is_float(&self) -> bool {
53        matches!(self, Self::Float(_))
54    }
55
56    pub fn as_f64(&self) -> Option<f64> {
57        match self {
58            Self::Float(inner) => Some(inner.value()),
59            _ => None,
60        }
61    }
62
63    pub fn is_string(&self) -> bool {
64        matches!(self, Self::String(_))
65    }
66
67    pub fn as_str(&self) -> Option<&'a str> {
68        match self {
69            Self::String(inner) => Some(inner.value()),
70            _ => None,
71        }
72    }
73
74    pub fn is_boolean(&self) -> bool {
75        matches!(self, Self::Boolean(_))
76    }
77
78    pub fn as_bool(&self) -> Option<bool> {
79        match self {
80            Self::Boolean(boolean_value) => Some(boolean_value.value()),
81            _ => None,
82        }
83    }
84
85    pub fn is_null(&self) -> bool {
86        matches!(self, Self::Null(_))
87    }
88
89    pub fn as_null(&self) -> Option<()> {
90        match self {
91            Self::Null(_) => Some(()),
92            _ => None,
93        }
94    }
95
96    pub fn is_enum(&self) -> bool {
97        matches!(self, Self::Enum(_))
98    }
99
100    pub fn as_enum_value(&self) -> Option<&'a str> {
101        match self {
102            Self::Enum(value) => Some(value.name()),
103            _ => None,
104        }
105    }
106
107    pub fn is_list(&self) -> bool {
108        matches!(self, Self::List(_))
109    }
110
111    pub fn as_list(&self) -> Option<ConstList<'a>> {
112        match self {
113            Self::List(inner) => Some(*inner),
114            _ => None,
115        }
116    }
117
118    pub fn as_items(&self) -> Option<Iter<'a, ConstValue<'a>>> {
119        match self {
120            Self::List(inner) => Some(inner.items()),
121            _ => None,
122        }
123    }
124
125    pub fn is_object(&self) -> bool {
126        matches!(self, Self::Object(_))
127    }
128
129    pub fn as_object(&self) -> Option<ConstObject<'a>> {
130        match self {
131            Self::Object(inner) => Some(*inner),
132            _ => None,
133        }
134    }
135
136    pub fn as_fields(&self) -> Option<Iter<'a, ConstObjectField<'a>>> {
137        match self {
138            Self::Object(inner) => Some(inner.fields()),
139            _ => None,
140        }
141    }
142}
143
144impl PartialEq for ConstValue<'_> {
145    #[allow(clippy::cmp_owned)]
146    fn eq(&self, other: &Self) -> bool {
147        Value::from(*self) == Value::from(*other)
148    }
149}
150
151impl PartialEq<Value<'_>> for ConstValue<'_> {
152    #[allow(clippy::cmp_owned)]
153    fn eq(&self, other: &Value<'_>) -> bool {
154        Value::from(*self) == *other
155    }
156}
157
158impl PartialEq<ConstValue<'_>> for Value<'_> {
159    #[allow(clippy::cmp_owned)]
160    fn eq(&self, other: &ConstValue<'_>) -> bool {
161        *self == Value::from(*other)
162    }
163}
164
165impl<'a> ValueStoreReader<'a> for ConstValue<'a> {
166    type Id = ConstValueId;
167}
168
169impl super::ValueStoreId for ConstValueId {
170    type Reader<'a> = ConstValue<'a>;
171
172    fn read(self, store: &super::ValueStore) -> Self::Reader<'_> {
173        let value_id = ValueId::from(self);
174        let value_cursor = Cursor {
175            id: value_id,
176            store,
177        };
178        let cursor = Cursor { id: self, store };
179
180        match store.lookup(value_id).kind {
181            ValueKind::Variable(_) => unreachable!("variable found under ConstValueId"),
182            ValueKind::Int(_) => ConstValue::Int(IntValue(value_cursor)),
183            ValueKind::Float(_) => ConstValue::Float(FloatValue(value_cursor)),
184            ValueKind::String(_) => ConstValue::String(StringValue(value_cursor)),
185            ValueKind::Boolean(_) => ConstValue::Boolean(BooleanValue(value_cursor)),
186            ValueKind::Null => ConstValue::Null(NullValue(value_cursor)),
187            ValueKind::Enum(_) => ConstValue::Enum(EnumValue(value_cursor)),
188            ValueKind::List(_) => ConstValue::List(ConstList(cursor)),
189            ValueKind::Object(_) => ConstValue::Object(ConstObject(cursor)),
190        }
191    }
192}
193
194impl<'a> TryFrom<Value<'a>> for ConstValue<'a> {
195    type Error = ();
196
197    fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
198        if !const_safe(value) {
199            return Err(());
200        }
201
202        Ok(match value {
203            Value::Variable(_) => unreachable!(),
204            Value::Int(int_value) => ConstValue::Int(int_value),
205            Value::Float(float_value) => ConstValue::Float(float_value),
206            Value::String(string_value) => ConstValue::String(string_value),
207            Value::Boolean(boolean_value) => ConstValue::Boolean(boolean_value),
208            Value::Null(null_value) => ConstValue::Null(null_value),
209            Value::Enum(enum_value) => ConstValue::Enum(enum_value),
210            Value::List(list_value) => {
211                let id = ConstValueId::new(list_value.0.id.get());
212                ConstValue::List(ConstList(Cursor {
213                    id,
214                    store: list_value.0.store,
215                }))
216            }
217            Value::Object(object) => {
218                let id = ConstValueId::new(object.0.id.get());
219                ConstValue::Object(ConstObject(Cursor {
220                    id,
221                    store: object.0.store,
222                }))
223            }
224        })
225    }
226}
227
228fn const_safe(value: Value<'_>) -> bool {
229    match value {
230        Value::Variable(_) => false,
231        Value::Int(_)
232        | Value::Float(_)
233        | Value::String(_)
234        | Value::Boolean(_)
235        | Value::Null(_)
236        | Value::Enum(_) => true,
237        Value::List(items) => items.items().all(const_safe),
238        Value::Object(object) => object.fields().all(|field| const_safe(field.value())),
239    }
240}