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)]
13pub enum Value<'a> {
15 #[value_variant]
17 Value(InnerValue<Value<'a>>),
18 Label(GLLBlockLabel<'a>),
20}
21
22#[derive(Debug)]
23pub enum ValueError<'a> {
25 ValueError(InnerValueError<Value<'a>>),
27 ConvertToLabel(Value<'a>)
29}
30
31pub 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<'_> { 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 { #[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}