Skip to main content

wagon_gll/
value.rs

1use std::collections::BTreeMap;
2use std::{fmt::Display, write, error::Error};
3
4use crate::GLLBlockLabel;
5pub(crate) use wagon_value::Value as InnerValue;
6pub(crate) use wagon_value::ValueError as InnerValueError;
7pub(crate) use wagon_value::ValueResult as InnerValueResult;
8pub use wagon_value::Valueable;
9
10use wagon_macros::ValueOps;
11
12#[derive(Debug, Eq, Hash, Clone, ValueOps)]
13/// An extension of [`wagon_value::Value`] that adds [`GLLBlockLabel`] as a possible type.
14pub enum Value<'a> {
15    /// Any regular [`wagon_value::Value`]
16    #[value_variant]
17    Value(InnerValue<Value<'a>>),
18    /// A [`GLLBlockLabel`]
19	Label(GLLBlockLabel<'a>),
20}
21
22#[derive(Debug)]
23/// An extension of [`wagon_value::ValueError`] for specific errors related to dealing with [`GLLBlockLabel`].
24pub enum ValueError<'a> {
25    /// Any regular [`wagon_value::ValueError`]
26    ValueError(InnerValueError<Value<'a>>),
27    /// An error occured trying to convert a [`Value`] to a [`GLLBlockLabel`].
28    ConvertToLabel(Value<'a>)
29}
30
31/// An quick result that either returns `T` or a [`ValueError`].
32pub type ValueResult<'a, T> = Result<T, ValueError<'a>>;
33
34impl<'a> From<InnerValueError<Value<'a>>> for ValueError<'a> {
35    fn from(value: InnerValueError<Value<'a>>) -> Self {
36        Self::ValueError(value)
37    }
38}
39
40impl<'a> From<InnerValueError<InnerValue<Value<'a>>>> for ValueError<'a> {
41    fn from(value: InnerValueError<InnerValue<Value<'a>>>) -> Self {
42        Self::ValueError(value.into())
43    }
44}
45
46impl Display for ValueError<'_> {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        match self {
49            ValueError::ValueError(e) => e.fmt(f),
50            ValueError::ConvertToLabel(v) => write!(f, "Failed converting {v} to label"),
51        }
52    }
53}
54
55impl Error for ValueError<'static> {
56    fn source(&self) -> Option<&(dyn Error + 'static)> {
57        match self {
58            ValueError::ValueError(e) => Some(e),
59            ValueError::ConvertToLabel(_) => None,
60        }
61    }
62}
63
64impl<'a> Valueable for Value<'a> {
65    fn is_truthy(&self) -> InnerValueResult<bool, Self> {
66        match self {
67            Value::Value(v) => Ok(v.is_truthy()?),
68            Value::Label(l) => Ok(l.is_eps()),
69        }
70    }
71
72    fn to_int(&self) -> InnerValueResult<i32, Self> {
73        match self {
74            Value::Value(v) => Ok(v.to_int()?),
75            o @ Value::Label(_) => Ok(i32::from(o.is_truthy()?))
76        }
77    }
78
79    fn to_float(&self) -> InnerValueResult<f32, Self> {
80        match self {
81            Value::Value(v) => Ok(v.to_float()?),
82            o @ Value::Label(_) => Ok(if o.is_truthy()? { 1.0 } else { 0.0 })
83        }
84    }
85
86    fn display_numerical(&self) -> InnerValueResult<String, Self> {
87        match self {
88            Value::Value(v) => Ok(v.display_numerical()?),
89            other @ Value::Label(_) => Ok(other.to_int()?.to_string())
90        }
91    }
92}
93
94impl PartialEq for Value<'_> { // For some reason the derive breaks but just copying it over is fine
95    fn eq(&self, other: &Self) -> bool {
96        match (self, other) {
97            (Value::Value(f0_self), Value::Value(f0_other)) => f0_self.eq(f0_other),
98            (Value::Label(f0_self), Value::Label(f0_other)) => f0_self.eq(f0_other),
99            _unused => false,
100        }
101    }
102}
103
104impl Display for Value<'_> {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        match self {
107            Value::Value(v) => write!(f, "{v}"),
108            Value::Label(v) => write!(f, "{}", v.to_string()),
109        }
110    }
111}
112
113impl From<Value<'_>> for i32 { // Can't genericize these because Rust doesn't allow it
114    #[allow(clippy::expect_used)]
115    fn from(value: Value) -> Self {
116        value.to_int().expect("This conversion can not fail")
117    }
118}
119
120impl From<Value<'_>> for f32 {
121    #[allow(clippy::expect_used)]
122    fn from(value: Value) -> Self {
123        value.to_float().expect("This conversion can not fail")
124    }
125}
126
127impl From<Value<'_>> for bool {
128    #[allow(clippy::expect_used)]
129    fn from(value: Value) -> Self {
130        value.is_truthy().expect("This conversion can not fail")
131    }
132}
133
134impl<'a> From<bool> for Value<'a> {
135    fn from(value: bool) -> Self {
136        Self::Value(InnerValue::Bool(value))
137    }
138}
139
140impl<'a> From<String> for Value<'a> {
141    fn from(value: String) -> Self {
142        Self::Value(InnerValue::String(value))
143    }
144}
145
146impl<'a> From<i32> for Value<'a> {
147    fn from(value: i32) -> Self {
148        Self::Value(InnerValue::Natural(value))
149    }
150}
151
152impl<'a> From<BTreeMap<String, Value<'a>>> for Value<'a> {
153    fn from(value: BTreeMap<String, Value<'a>>) -> Self {
154        Self::Value(InnerValue::Dict(value))
155    }
156}
157
158impl<'a> From<Vec<Value<'a>>> for Value<'a> {
159    fn from(value: Vec<Value<'a>>) -> Self {
160        Self::Value(InnerValue::Array(value))
161    }
162}
163
164impl<'a> From<InnerValue<Value<'a>>> for Value<'a> {
165    fn from(value: InnerValue<Value<'a>>) -> Self {
166        Self::Value(value)
167    }
168}
169
170impl<'a> TryFrom<f32> for Value<'a> {
171    type Error = ValueError<'a>;
172
173    fn try_from(value: f32) -> Result<Self, Self::Error> {
174        match InnerValue::try_from(value) {
175            Ok(v) => Ok(Self::Value(v)),
176            Err(e) => Err(InnerValueError::<Self>::from(e).into()),
177        }
178    }
179}
180
181impl<'a> TryFrom<Value<'a>> for GLLBlockLabel<'a> {
182    type Error = ValueError<'a>;
183
184    fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
185        match value {
186            Value::Label(l) => Ok(l),
187            other @ Value::Value(_) => Err(ValueError::ConvertToLabel(other))
188        }
189    }
190}
191
192impl<'a> TryFrom<Value<'a>> for InnerValue<Value<'a>> {
193    type Error = InnerValueError<Value<'a>>;
194
195    fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
196        match value {
197            Value::Value(v) => Ok(v),
198            other @ Value::Label(_) => Err(InnerValueError::ConversionError(other)),
199        }
200    }
201}
202
203impl<'a> std::ops::Not for Value<'a> {
204    type Output = ValueResult<'a, Self>;
205
206    fn not(self) -> Self::Output {
207        match self {
208            Value::Value(v) => Ok(Value::Value((!v)?)),
209            v @ Value::Label(_) => Err(InnerValueError::NegationError(v).into())
210        }
211    }
212}
213
214impl<'a> PartialOrd for Value<'a> {
215    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
216        match (self, other) {
217            (Value::Value(v1), Value::Value(v2)) => v1.partial_cmp(v2),
218            _ => None
219        }
220    }
221}
222
223impl<'a> PartialEq<InnerValue<Self>> for Value<'a> {
224    fn eq(&self, other: &InnerValue<Self>) -> bool {
225        match self {
226            Value::Value(v) => v == other,
227            Value::Label(_) => false,
228        }
229    }
230}
231
232impl<'a> PartialEq<Value<'a>> for InnerValue<Value<'a>> {
233    fn eq(&self, other: &Value<'a>) -> bool {
234        match other {
235            Value::Value(v) => v == self,
236            Value::Label(_) => false,
237        }
238    }
239}
240
241impl<'a> PartialOrd<InnerValue<Self>> for Value<'a> {
242    fn partial_cmp(&self, other: &InnerValue<Self>) -> Option<std::cmp::Ordering> {
243        match self {
244            Value::Value(v) => v.partial_cmp(other),
245            Value::Label(_) => None,
246        }
247    }
248}
249
250impl<'a> PartialOrd<Value<'a>> for InnerValue<Value<'a>> {
251    fn partial_cmp(&self, other: &Value<'a>) -> Option<std::cmp::Ordering> {
252        match other {
253            Value::Value(v) => self.partial_cmp(v),
254            Value::Label(_) => None,
255        }
256    }
257}