1use super::config::ValueKind;
4use super::path::Path;
5use super::rules::Shape;
6use crate::base::{Error, ErrorKind, ExprCause};
7use datalogic_rs::Logic;
8use datavalue::{DataValue, NumberValue, OwnedDataValue};
9use serde_json::Value;
10use std::borrow::Cow;
11use std::fmt;
12use std::str::FromStr;
13
14pub(crate) mod sealed {
15 use datalogic_rs::{DataValue, Logic};
16 use datavalue::OwnedDataValue;
17
18 pub trait Sealed {}
19
20 #[derive(Clone, Copy, Debug)]
26 pub struct Crate(());
27
28 pub(crate) const CRATE: Crate = Crate(());
30
31 pub trait SealedExpr {
34 fn constant_value(&self, _: Crate) -> Option<OwnedDataValue>;
37
38 fn logic(&self, _: Crate) -> &Logic;
40
41 fn reads_secret(&self, _: Crate) -> bool;
43
44 fn value_of(
48 &self,
49 view: &DataValue<'_>,
50 ops: Option<u64>,
51 _: Crate,
52 ) -> crate::Result<OwnedDataValue>;
53 }
54}
55
56pub trait FromValue: Sized + Clone + Send + Sync + 'static + sealed::Sealed {
67 #[doc(hidden)]
69 const KIND: ValueKind;
70
71 type Out<'a>;
74
75 #[doc(hidden)]
76 fn from_view(v: &DataValue<'_>) -> Result<Self, String>;
77 #[doc(hidden)]
78 fn lend(c: &Self) -> Self::Out<'_>;
79 #[doc(hidden)]
80 fn give<'a>(v: Self) -> Self::Out<'a>;
81 #[doc(hidden)]
83 fn to_value(c: &Self) -> OwnedDataValue {
84 Self::into_value(c.clone())
85 }
86 #[doc(hidden)]
88 fn into_value(v: Self) -> OwnedDataValue;
89 #[doc(hidden)]
91 fn type_name() -> &'static str;
92}
93
94impl sealed::Sealed for OwnedDataValue {}
95impl sealed::Sealed for String {}
96impl sealed::Sealed for u64 {}
97impl sealed::Sealed for i64 {}
98impl sealed::Sealed for f64 {}
99impl sealed::Sealed for bool {}
100impl sealed::Sealed for Path {}
101
102impl FromValue for OwnedDataValue {
103 const KIND: ValueKind = ValueKind::Any;
104 type Out<'a> = Cow<'a, Self>;
105 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
106 Ok(v.to_owned())
107 }
108 fn lend(c: &Self) -> Self::Out<'_> {
109 Cow::Borrowed(c)
110 }
111 fn give<'a>(v: Self) -> Self::Out<'a> {
112 Cow::Owned(v)
113 }
114 fn into_value(v: Self) -> OwnedDataValue {
115 v
116 }
117 fn type_name() -> &'static str {
118 "a value"
119 }
120}
121
122impl FromValue for String {
123 const KIND: ValueKind = ValueKind::String;
124 type Out<'a> = Cow<'a, str>;
125 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
128 Ok(match v {
129 DataValue::String(s) => (*s).to_owned(),
130 other => other.to_string(),
131 })
132 }
133 fn lend(c: &Self) -> Self::Out<'_> {
134 Cow::Borrowed(c)
135 }
136 fn give<'a>(v: Self) -> Self::Out<'a> {
137 Cow::Owned(v)
138 }
139 fn into_value(v: Self) -> OwnedDataValue {
140 OwnedDataValue::String(v)
141 }
142 fn type_name() -> &'static str {
143 "a string"
144 }
145}
146
147impl FromValue for u64 {
148 const KIND: ValueKind = ValueKind::Number;
149 type Out<'a> = Self;
150 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
151 match v {
152 DataValue::Number(n) => n
153 .as_u64()
154 .ok_or_else(|| "a negative or fractional number is not a u64".to_owned()),
155 other => Err(format!("{} is not a u64", Shape::of_view(other).describe())),
156 }
157 }
158 fn lend(c: &Self) -> Self::Out<'_> {
159 *c
160 }
161 fn give<'a>(v: Self) -> Self::Out<'a> {
162 v
163 }
164 fn into_value(v: Self) -> OwnedDataValue {
165 v.into()
166 }
167 fn type_name() -> &'static str {
168 "a u64"
169 }
170}
171
172impl FromValue for i64 {
173 const KIND: ValueKind = ValueKind::Number;
174 type Out<'a> = Self;
175 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
177 match v {
178 DataValue::Number(n) => n
179 .as_i64()
180 .ok_or_else(|| "an out-of-range or fractional number is not an i64".to_owned()),
181 other => Err(format!(
182 "{} is not an i64",
183 Shape::of_view(other).describe()
184 )),
185 }
186 }
187 fn lend(c: &Self) -> Self::Out<'_> {
188 *c
189 }
190 fn give<'a>(v: Self) -> Self::Out<'a> {
191 v
192 }
193 fn into_value(v: Self) -> OwnedDataValue {
194 v.into()
195 }
196 fn type_name() -> &'static str {
197 "an i64"
198 }
199}
200
201impl FromValue for f64 {
202 const KIND: ValueKind = ValueKind::Number;
203 type Out<'a> = Self;
204 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
207 match v {
208 DataValue::Number(n) if n.as_f64().is_finite() => Ok(n.as_f64()),
209 DataValue::Number(_) => Err("a non-finite number is not a finite f64".to_owned()),
210 other => Err(format!(
211 "{} is not an f64",
212 Shape::of_view(other).describe()
213 )),
214 }
215 }
216 fn lend(c: &Self) -> Self::Out<'_> {
217 *c
218 }
219 fn give<'a>(v: Self) -> Self::Out<'a> {
220 v
221 }
222 fn into_value(v: Self) -> OwnedDataValue {
224 OwnedDataValue::Number(NumberValue::Float(v))
225 }
226 fn type_name() -> &'static str {
227 "an f64"
228 }
229}
230
231impl FromValue for bool {
232 const KIND: ValueKind = ValueKind::Bool;
233 type Out<'a> = Self;
234 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
235 match v {
236 DataValue::Bool(b) => Ok(*b),
237 other => Err(format!(
238 "{} is not a bool",
239 Shape::of_view(other).describe()
240 )),
241 }
242 }
243 fn lend(c: &Self) -> Self::Out<'_> {
244 *c
245 }
246 fn give<'a>(v: Self) -> Self::Out<'a> {
247 v
248 }
249 fn into_value(v: Self) -> OwnedDataValue {
250 v.into()
251 }
252 fn type_name() -> &'static str {
253 "a bool"
254 }
255}
256
257impl FromValue for Path {
258 const KIND: ValueKind = ValueKind::Path;
259 type Out<'a> = Cow<'a, Self>;
260 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
261 match v {
262 DataValue::String(s) => Self::from_str(s).map_err(|e| e.message().to_owned()),
263 other => Err(format!(
264 "{} is not a path",
265 Shape::of_view(other).describe()
266 )),
267 }
268 }
269 fn lend(c: &Self) -> Self::Out<'_> {
270 Cow::Borrowed(c)
271 }
272 fn give<'a>(v: Self) -> Self::Out<'a> {
273 Cow::Owned(v)
274 }
275 fn into_value(v: Self) -> OwnedDataValue {
276 OwnedDataValue::String(v.to_string())
277 }
278 fn type_name() -> &'static str {
279 "a path"
280 }
281}
282
283#[derive(Clone, Debug, PartialEq)]
285#[non_exhaustive]
286pub struct Evaluated<T> {
287 pub value: T,
289 pub ops: Option<u64>,
292}
293
294pub struct Expr<T: FromValue = OwnedDataValue> {
300 pub(super) raw: Value,
301 pub(super) logic: Logic,
302 pub(super) constant: Option<T>,
303 pub(super) reads_secret: bool,
304}
305
306pub(crate) fn snippet(raw: &Value) -> String {
309 const MAX: usize = 120;
310 let text = raw.to_string();
311 if text.len() <= MAX {
312 return text;
313 }
314 let end = text.floor_char_boundary(MAX);
315 format!("{}…", &text[..end])
316}
317
318impl Expr<OwnedDataValue> {
319 pub(crate) fn is_trivially_true(&self) -> bool {
323 self.constant() == Some(&OwnedDataValue::Bool(true))
324 }
325}
326
327impl<T: FromValue> Expr<T> {
328 pub fn constant(&self) -> Option<&T> {
330 self.constant.as_ref()
331 }
332
333 pub fn raw(&self) -> &Value {
335 &self.raw
336 }
337
338 pub(crate) fn logic(&self) -> &Logic {
340 &self.logic
341 }
342
343 pub(crate) fn reads_secret(&self) -> bool {
345 self.reads_secret
346 }
347
348 pub(crate) fn convert(&self, view: &DataValue<'_>, ops: Option<u64>) -> crate::Result<T> {
353 T::from_view(view).map_err(|why| {
354 let shown = snippet(&self.raw);
355 let message = if self.reads_secret {
356 format!("`{shown}` did not give {}", T::type_name())
357 } else {
358 format!("`{shown}` did not give {}: {why}", T::type_name())
359 };
360 Error::new(ErrorKind::Eval, message).with_expr_cause(ExprCause::type_mismatch(ops))
361 })
362 }
363}
364
365impl<T: FromValue> fmt::Debug for Expr<T> {
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 f.debug_struct("Expr")
368 .field("raw", &self.raw)
369 .field("folded", &self.constant.is_some())
370 .finish()
371 }
372}
373
374pub trait ResolveExpr: Send + Sync + sealed::SealedExpr {
389 fn raw(&self) -> &Value;
391}
392
393impl<T: FromValue> ResolveExpr for Expr<T> {
394 fn raw(&self) -> &Value {
395 &self.raw
396 }
397}
398
399impl<T: FromValue> sealed::SealedExpr for Expr<T> {
400 fn constant_value(&self, _: sealed::Crate) -> Option<OwnedDataValue> {
401 self.constant.as_ref().map(T::to_value)
402 }
403
404 fn logic(&self, _: sealed::Crate) -> &Logic {
405 &self.logic
406 }
407
408 fn reads_secret(&self, _: sealed::Crate) -> bool {
409 self.reads_secret
410 }
411
412 fn value_of(
413 &self,
414 view: &DataValue<'_>,
415 ops: Option<u64>,
416 _: sealed::Crate,
417 ) -> crate::Result<OwnedDataValue> {
418 self.convert(view, ops).map(T::into_value)
419 }
420}