1use super::config::ValueKind;
4use super::path::Path;
5use super::rules::Shape;
6use super::walk::reads_secret;
7use crate::base::{Error, ErrorKind};
8use datalogic_rs::Logic;
9use datavalue::{DataValue, NumberValue, OwnedDataValue};
10use serde_json::Value;
11use std::borrow::Cow;
12use std::fmt;
13use std::str::FromStr;
14
15pub(crate) mod sealed {
16 use datalogic_rs::{DataValue, Logic};
17 use datavalue::OwnedDataValue;
18
19 pub trait Sealed {}
20
21 #[derive(Clone, Copy, Debug)]
27 pub struct Crate(());
28
29 pub(crate) const CRATE: Crate = Crate(());
31
32 pub trait SealedExpr {
35 fn constant_value(&self, _: Crate) -> Option<OwnedDataValue>;
38
39 fn logic(&self, _: Crate) -> &Logic;
41
42 fn value_of(&self, view: &DataValue<'_>, _: Crate) -> crate::Result<OwnedDataValue>;
46 }
47}
48
49pub trait FromValue: Sized + Clone + Send + Sync + 'static + sealed::Sealed {
60 #[doc(hidden)]
62 const KIND: ValueKind;
63
64 type Out<'a>;
67
68 #[doc(hidden)]
69 fn from_view(v: &DataValue<'_>) -> Result<Self, String>;
70 #[doc(hidden)]
71 fn lend(c: &Self) -> Self::Out<'_>;
72 #[doc(hidden)]
73 fn give<'a>(v: Self) -> Self::Out<'a>;
74 #[doc(hidden)]
76 fn to_value(c: &Self) -> OwnedDataValue {
77 Self::into_value(c.clone())
78 }
79 #[doc(hidden)]
81 fn into_value(v: Self) -> OwnedDataValue;
82 #[doc(hidden)]
84 fn type_name() -> &'static str;
85}
86
87impl sealed::Sealed for OwnedDataValue {}
88impl sealed::Sealed for String {}
89impl sealed::Sealed for u64 {}
90impl sealed::Sealed for i64 {}
91impl sealed::Sealed for f64 {}
92impl sealed::Sealed for bool {}
93impl sealed::Sealed for Path {}
94
95impl FromValue for OwnedDataValue {
96 const KIND: ValueKind = ValueKind::Any;
97 type Out<'a> = Cow<'a, Self>;
98 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
99 Ok(v.to_owned())
100 }
101 fn lend(c: &Self) -> Self::Out<'_> {
102 Cow::Borrowed(c)
103 }
104 fn give<'a>(v: Self) -> Self::Out<'a> {
105 Cow::Owned(v)
106 }
107 fn into_value(v: Self) -> OwnedDataValue {
108 v
109 }
110 fn type_name() -> &'static str {
111 "a value"
112 }
113}
114
115impl FromValue for String {
116 const KIND: ValueKind = ValueKind::String;
117 type Out<'a> = Cow<'a, str>;
118 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
121 Ok(match v {
122 DataValue::String(s) => (*s).to_owned(),
123 other => other.to_string(),
124 })
125 }
126 fn lend(c: &Self) -> Self::Out<'_> {
127 Cow::Borrowed(c)
128 }
129 fn give<'a>(v: Self) -> Self::Out<'a> {
130 Cow::Owned(v)
131 }
132 fn into_value(v: Self) -> OwnedDataValue {
133 OwnedDataValue::String(v)
134 }
135 fn type_name() -> &'static str {
136 "a string"
137 }
138}
139
140impl FromValue for u64 {
141 const KIND: ValueKind = ValueKind::Number;
142 type Out<'a> = Self;
143 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
144 match v {
145 DataValue::Number(n) => n
146 .as_u64()
147 .ok_or_else(|| "a negative or fractional number is not a u64".to_owned()),
148 other => Err(format!("{} is not a u64", Shape::of_view(other).describe())),
149 }
150 }
151 fn lend(c: &Self) -> Self::Out<'_> {
152 *c
153 }
154 fn give<'a>(v: Self) -> Self::Out<'a> {
155 v
156 }
157 fn into_value(v: Self) -> OwnedDataValue {
158 v.into()
159 }
160 fn type_name() -> &'static str {
161 "a u64"
162 }
163}
164
165impl FromValue for i64 {
166 const KIND: ValueKind = ValueKind::Number;
167 type Out<'a> = Self;
168 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
170 match v {
171 DataValue::Number(n) => n
172 .as_i64()
173 .ok_or_else(|| "an out-of-range or fractional number is not an i64".to_owned()),
174 other => Err(format!(
175 "{} is not an i64",
176 Shape::of_view(other).describe()
177 )),
178 }
179 }
180 fn lend(c: &Self) -> Self::Out<'_> {
181 *c
182 }
183 fn give<'a>(v: Self) -> Self::Out<'a> {
184 v
185 }
186 fn into_value(v: Self) -> OwnedDataValue {
187 v.into()
188 }
189 fn type_name() -> &'static str {
190 "an i64"
191 }
192}
193
194impl FromValue for f64 {
195 const KIND: ValueKind = ValueKind::Number;
196 type Out<'a> = Self;
197 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
200 match v {
201 DataValue::Number(n) if n.as_f64().is_finite() => Ok(n.as_f64()),
202 DataValue::Number(_) => Err("a non-finite number is not a finite f64".to_owned()),
203 other => Err(format!(
204 "{} is not an f64",
205 Shape::of_view(other).describe()
206 )),
207 }
208 }
209 fn lend(c: &Self) -> Self::Out<'_> {
210 *c
211 }
212 fn give<'a>(v: Self) -> Self::Out<'a> {
213 v
214 }
215 fn into_value(v: Self) -> OwnedDataValue {
217 OwnedDataValue::Number(NumberValue::Float(v))
218 }
219 fn type_name() -> &'static str {
220 "an f64"
221 }
222}
223
224impl FromValue for bool {
225 const KIND: ValueKind = ValueKind::Bool;
226 type Out<'a> = Self;
227 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
228 match v {
229 DataValue::Bool(b) => Ok(*b),
230 other => Err(format!(
231 "{} is not a bool",
232 Shape::of_view(other).describe()
233 )),
234 }
235 }
236 fn lend(c: &Self) -> Self::Out<'_> {
237 *c
238 }
239 fn give<'a>(v: Self) -> Self::Out<'a> {
240 v
241 }
242 fn into_value(v: Self) -> OwnedDataValue {
243 v.into()
244 }
245 fn type_name() -> &'static str {
246 "a bool"
247 }
248}
249
250impl FromValue for Path {
251 const KIND: ValueKind = ValueKind::Path;
252 type Out<'a> = Cow<'a, Self>;
253 fn from_view(v: &DataValue<'_>) -> Result<Self, String> {
254 match v {
255 DataValue::String(s) => Self::from_str(s).map_err(|e| e.message().to_owned()),
256 other => Err(format!(
257 "{} is not a path",
258 Shape::of_view(other).describe()
259 )),
260 }
261 }
262 fn lend(c: &Self) -> Self::Out<'_> {
263 Cow::Borrowed(c)
264 }
265 fn give<'a>(v: Self) -> Self::Out<'a> {
266 Cow::Owned(v)
267 }
268 fn into_value(v: Self) -> OwnedDataValue {
269 OwnedDataValue::String(v.to_string())
270 }
271 fn type_name() -> &'static str {
272 "a path"
273 }
274}
275
276#[derive(Clone, Debug, PartialEq)]
278#[non_exhaustive]
279pub struct Evaluated<T> {
280 pub value: T,
282 pub ops: Option<u64>,
285}
286
287pub struct Expr<T: FromValue = OwnedDataValue> {
293 pub(super) raw: Value,
294 pub(super) logic: Logic,
295 pub(super) constant: Option<T>,
296}
297
298pub(crate) fn snippet(raw: &Value) -> String {
301 const MAX: usize = 120;
302 let text = raw.to_string();
303 if text.len() <= MAX {
304 return text;
305 }
306 let end = text.floor_char_boundary(MAX);
307 format!("{}…", &text[..end])
308}
309
310impl Expr<OwnedDataValue> {
311 pub(crate) fn is_trivially_true(&self) -> bool {
315 self.constant() == Some(&OwnedDataValue::Bool(true))
316 }
317}
318
319impl<T: FromValue> Expr<T> {
320 pub fn constant(&self) -> Option<&T> {
322 self.constant.as_ref()
323 }
324
325 pub fn raw(&self) -> &Value {
327 &self.raw
328 }
329
330 pub(crate) fn logic(&self) -> &Logic {
332 &self.logic
333 }
334
335 pub(crate) fn convert(&self, view: &DataValue<'_>) -> crate::Result<T> {
339 T::from_view(view).map_err(|why| {
340 let shown = snippet(&self.raw);
341 let message = if reads_secret(&self.raw) {
342 format!("`{shown}` did not give {}", T::type_name())
343 } else {
344 format!("`{shown}` did not give {}: {why}", T::type_name())
345 };
346 Error::new(ErrorKind::Eval, message)
347 })
348 }
349}
350
351impl<T: FromValue> fmt::Debug for Expr<T> {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 f.debug_struct("Expr")
354 .field("raw", &self.raw)
355 .field("folded", &self.constant.is_some())
356 .finish()
357 }
358}
359
360pub trait ResolveExpr: Send + Sync + sealed::SealedExpr {
375 fn raw(&self) -> &Value;
377}
378
379impl<T: FromValue> ResolveExpr for Expr<T> {
380 fn raw(&self) -> &Value {
381 &self.raw
382 }
383}
384
385impl<T: FromValue> sealed::SealedExpr for Expr<T> {
386 fn constant_value(&self, _: sealed::Crate) -> Option<OwnedDataValue> {
387 self.constant.as_ref().map(T::to_value)
388 }
389
390 fn logic(&self, _: sealed::Crate) -> &Logic {
391 &self.logic
392 }
393
394 fn value_of(&self, view: &DataValue<'_>, _: sealed::Crate) -> crate::Result<OwnedDataValue> {
395 self.convert(view).map(T::into_value)
396 }
397}