1use crate::path_mapping::PathFormat;
8use crate::range_expr::RangeExpr;
9use crate::types::{ExprType, TypeCode};
10
11#[derive(Debug, Clone, serde::Serialize)]
18pub struct Float64 {
19 value: f64,
20 original: Option<Box<str>>,
21}
22
23impl std::hash::Hash for Float64 {
24 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
25 self.value.to_bits().hash(state);
26 }
27}
28
29fn normalize_zero(v: f64) -> f64 {
31 if v == 0.0 {
32 0.0
33 } else {
34 v
35 }
36}
37
38impl Float64 {
39 pub fn new(v: f64) -> Result<Self, crate::error::ExpressionError> {
41 let v = normalize_zero(v);
42 if v.is_nan() {
43 return Err(crate::error::ExpressionError::float_error(
44 "Float operation produced NaN",
45 ));
46 }
47 if v.is_infinite() {
48 return Err(crate::error::ExpressionError::float_error(
49 "Float operation produced infinity",
50 ));
51 }
52 Ok(Self {
53 value: v,
54 original: None,
55 })
56 }
57 pub fn with_str(v: f64, s: String) -> Result<Self, crate::error::ExpressionError> {
59 let v = normalize_zero(v);
60 if v.is_nan() {
61 return Err(crate::error::ExpressionError::float_error(
62 "Float operation produced NaN",
63 ));
64 }
65 if v.is_infinite() {
66 return Err(crate::error::ExpressionError::float_error(
67 "Float operation produced infinity",
68 ));
69 }
70 Ok(Self {
71 value: v,
72 original: if v == 0.0 && s != "0.0" {
73 None
74 } else {
75 Some(s.into_boxed_str())
76 },
77 })
78 }
79 pub fn value(&self) -> f64 {
81 self.value
82 }
83 pub fn to_display_string(&self) -> String {
85 if let Some(s) = &self.original {
86 s.to_string()
87 } else {
88 format_float(self.value)
89 }
90 }
91}
92
93impl std::fmt::Display for Float64 {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 write!(f, "{}", self.to_display_string())
96 }
97}
98
99impl std::ops::Deref for Float64 {
100 type Target = f64;
101 fn deref(&self) -> &f64 {
102 &self.value
103 }
104}
105
106impl PartialEq<f64> for Float64 {
107 fn eq(&self, other: &f64) -> bool {
108 self.value == *other
109 }
110}
111
112impl PartialOrd<f64> for Float64 {
113 fn partial_cmp(&self, other: &f64) -> Option<std::cmp::Ordering> {
114 self.value.partial_cmp(other)
115 }
116}
117
118#[derive(Debug, Clone, serde::Serialize)]
128#[non_exhaustive]
129pub enum ExprValue {
130 Null,
131 Bool(bool),
132 Int(i64),
133 Float(Float64),
134 String(String),
135 #[non_exhaustive]
143 Path {
144 value: String,
145 format: PathFormat,
146 },
147 ListBool(Vec<bool>),
149 ListInt(Vec<i64>),
150 ListFloat(Vec<Float64>),
151 ListString(Vec<String>, usize), ListPath(Vec<String>, PathFormat, usize), ListList(Vec<ExprValue>, ExprType, usize), RangeExpr(RangeExpr),
155 Unresolved(ExprType),
156}
157
158impl std::hash::Hash for ExprValue {
159 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
160 match self {
164 Self::Null => 0u8.hash(state),
165 Self::Bool(b) => {
166 1u8.hash(state);
167 b.hash(state);
168 }
169 Self::Int(i) => {
171 2u8.hash(state);
172 i.hash(state);
173 }
174 Self::Float(f) => {
177 let v = f.value;
178 if v.fract() == 0.0 && v >= i64::MIN as f64 && v <= i64::MAX as f64 {
179 2u8.hash(state);
180 (v as i64).hash(state);
181 } else {
182 12u8.hash(state);
183 v.to_bits().hash(state);
184 }
185 }
186 Self::String(s) => {
188 3u8.hash(state);
189 s.hash(state);
190 }
191 Self::Path { value, .. } => {
192 3u8.hash(state);
193 value.hash(state);
194 }
195 Self::ListBool(v) => {
199 4u8.hash(state);
200 for b in v {
201 1u8.hash(state);
202 b.hash(state);
203 }
204 }
205 Self::ListInt(v) => {
206 4u8.hash(state);
207 for i in v {
208 2u8.hash(state);
209 i.hash(state);
210 }
211 }
212 Self::ListFloat(v) => {
213 4u8.hash(state);
214 for f in v {
215 let fv = f.value;
216 if fv.fract() == 0.0 && fv >= i64::MIN as f64 && fv <= i64::MAX as f64 {
217 2u8.hash(state);
218 (fv as i64).hash(state);
219 } else {
220 12u8.hash(state);
221 fv.to_bits().hash(state);
222 }
223 }
224 }
225 Self::ListString(v, _) => {
226 4u8.hash(state);
227 for s in v {
228 3u8.hash(state);
229 s.hash(state);
230 }
231 }
232 Self::ListPath(v, _, _) => {
233 4u8.hash(state);
234 for s in v {
235 3u8.hash(state);
236 s.hash(state);
237 }
238 }
239 Self::ListList(v, _, _) => {
240 4u8.hash(state);
241 for e in v {
242 e.hash(state);
243 }
244 }
245 Self::RangeExpr(r) => {
246 10u8.hash(state);
247 r.hash(state);
248 }
249 Self::Unresolved(t) => {
250 11u8.hash(state);
251 t.hash(state);
252 }
253 }
254 }
255}
256
257impl Eq for ExprValue {}
258
259impl ExprValue {
260 fn make_list_string(v: Vec<String>) -> Self {
262 let heap =
263 v.len() * std::mem::size_of::<String>() + v.iter().map(|s| s.len()).sum::<usize>();
264 Self::ListString(v, heap)
265 }
266 fn make_list_path(v: Vec<String>, fmt: PathFormat) -> Self {
267 let heap =
268 v.len() * std::mem::size_of::<String>() + v.iter().map(|s| s.len()).sum::<usize>();
269 Self::ListPath(v, fmt, heap)
270 }
271 fn make_list_list(v: Vec<ExprValue>, elem_hint: ExprType) -> Self {
272 let heap = v.len() * std::mem::size_of::<ExprValue>()
274 + v.iter().map(|e| e.heap_size()).sum::<usize>();
275 let elem_type = v.first().map(|e| e.expr_type()).unwrap_or(elem_hint);
276 Self::ListList(v, elem_type, heap)
277 }
278
279 fn estimate_list_heap_size(elements: &[ExprValue]) -> usize {
292 let per_slot = std::mem::size_of::<ExprValue>();
293 elements
294 .iter()
295 .fold(elements.len().saturating_mul(per_slot), |acc, e| {
296 acc.saturating_add(e.heap_size())
297 })
298 }
299
300 pub fn make_list_checked(
315 ctx: &mut dyn crate::function_library::EvalContext,
316 elements: Vec<ExprValue>,
317 hint_type: ExprType,
318 ) -> Result<Self, crate::error::ExpressionError> {
319 ctx.check_memory(Self::estimate_list_heap_size(&elements))?;
320 Self::make_list(elements, hint_type)
321 }
322
323 pub fn make_list(
335 mut elements: Vec<ExprValue>,
336 hint_type: ExprType,
337 ) -> Result<Self, crate::error::ExpressionError> {
338 if elements
342 .iter()
343 .any(|e| matches!(e, Self::ListList(_, et, _) if *et != ExprType::NULLTYPE))
344 {
345 return Err(crate::error::ExpressionError::new(
346 "Lists may be nested at most 2 levels deep",
347 ));
348 }
349 let has_empty_listlist = elements.iter().any(
352 |e| matches!(e, Self::ListList(v, et, _) if v.is_empty() && *et == ExprType::NULLTYPE),
353 );
354 if has_empty_listlist {
355 let sibling_code = elements.iter().find_map(|e| match e {
357 Self::ListBool(v) if !v.is_empty() => Some(crate::types::TypeCode::Bool),
358 Self::ListInt(v) if !v.is_empty() => Some(crate::types::TypeCode::Int),
359 Self::ListFloat(_) => Some(crate::types::TypeCode::Float),
360 Self::ListString(v, _) if !v.is_empty() => Some(crate::types::TypeCode::String),
361 Self::ListPath(v, _, _) if !v.is_empty() => Some(crate::types::TypeCode::Path),
362 _ => None,
363 });
364 if let Some(code) = sibling_code {
365 for e in &mut elements {
366 if matches!(e, Self::ListList(v, et, _) if v.is_empty() && *et == ExprType::NULLTYPE)
367 {
368 *e = match code {
369 crate::types::TypeCode::Bool => Self::ListBool(Vec::new()),
370 crate::types::TypeCode::Int => Self::ListInt(Vec::new()),
371 crate::types::TypeCode::Float => Self::ListFloat(Vec::new()),
372 crate::types::TypeCode::String => Self::ListString(Vec::new(), 0),
373 crate::types::TypeCode::Path => {
374 Self::make_list_path(Vec::new(), PathFormat::host())
375 }
376 _ => continue,
377 };
378 }
379 }
380 }
381 }
382 if elements.is_empty() {
383 return Ok(match hint_type.code() {
389 crate::types::TypeCode::Bool => Self::ListBool(Vec::new()),
390 crate::types::TypeCode::Int => Self::ListInt(Vec::new()),
391 crate::types::TypeCode::Float => Self::ListFloat(Vec::new()),
392 crate::types::TypeCode::Path => {
393 Self::make_list_path(Vec::new(), PathFormat::host())
394 }
395 crate::types::TypeCode::List => Self::make_list_list(Vec::new(), hint_type),
396 crate::types::TypeCode::String => Self::ListString(Vec::new(), 0),
397 crate::types::TypeCode::NullType => {
398 Self::ListList(Vec::new(), ExprType::NULLTYPE, 0)
399 }
400 _ => Self::ListList(Vec::new(), ExprType::NULLTYPE, 0),
401 });
402 }
403 let has_int = elements.iter().any(|e| matches!(e, Self::Int(_)));
404 let has_float = elements.iter().any(|e| matches!(e, Self::Float(_)));
405 if has_int && has_float {
406 for e in &mut elements {
407 if let Self::Int(i) = e {
408 *e = Self::Float(Float64::new(*i as f64).unwrap());
409 }
410 }
411 return Ok(Self::ListFloat(
412 elements
413 .into_iter()
414 .map(|e| match e {
415 Self::Float(f) => f,
416 _ => unreachable!("all elements promoted to Float above"),
417 })
418 .collect(),
419 ));
420 }
421 let has_list_int = elements
422 .iter()
423 .any(|e| e.is_list() && e.list_elem_type() == Some(ExprType::INT));
424 let has_list_float = elements
425 .iter()
426 .any(|e| e.is_list() && e.list_elem_type() == Some(ExprType::FLOAT));
427 if has_list_int && has_list_float {
428 for e in &mut elements {
429 if let Self::ListInt(ints) = e {
430 *e = Self::ListFloat(
431 ints.iter()
432 .map(|i| Float64::new(*i as f64).unwrap())
433 .collect(),
434 );
435 }
436 }
437 return Ok(Self::make_list_list(elements, ExprType::NULLTYPE));
438 }
439 let has_list_path = elements
441 .iter()
442 .any(|e| e.is_list() && e.list_elem_type() == Some(ExprType::PATH));
443 let has_list_string = elements
444 .iter()
445 .any(|e| e.is_list() && e.list_elem_type() == Some(ExprType::STRING));
446 if has_list_path && has_list_string {
447 for e in &mut elements {
448 if let Self::ListPath(paths, _, _) = e {
449 *e = Self::make_list_string(std::mem::take(paths));
450 }
451 }
452 return Ok(Self::make_list_list(elements, ExprType::NULLTYPE));
453 }
454 let has_path = elements.iter().any(|e| matches!(e, Self::Path { .. }));
456 let has_string = elements.iter().any(|e| matches!(e, Self::String(_)));
457 if has_path && has_string {
458 return Ok(Self::make_list_string(
459 elements
460 .into_iter()
461 .map(|e| match e {
462 Self::String(s) | Self::Path { value: s, .. } => s,
463 _ => e.to_display_string(),
464 })
465 .collect(),
466 ));
467 }
468 Ok(match &elements[0] {
469 Self::Bool(_) => Self::ListBool(
470 elements
471 .into_iter()
472 .map(|e| match e {
473 Self::Bool(b) => Ok(b),
474 _ => Err(crate::error::ExpressionError::type_error(format!(
475 "make_list expected bool element, got {}",
476 e.type_name()
477 ))),
478 })
479 .collect::<Result<_, _>>()?,
480 ),
481 Self::Int(_) => Self::ListInt(
482 elements
483 .into_iter()
484 .map(|e| match e {
485 Self::Int(i) => Ok(i),
486 _ => Err(crate::error::ExpressionError::type_error(format!(
487 "make_list expected int element, got {}",
488 e.type_name()
489 ))),
490 })
491 .collect::<Result<_, _>>()?,
492 ),
493 Self::Float(_) => Self::ListFloat(
494 elements
495 .into_iter()
496 .map(|e| match e {
497 Self::Float(f) => Ok(f),
498 _ => Err(crate::error::ExpressionError::type_error(format!(
499 "make_list expected float element, got {}",
500 e.type_name()
501 ))),
502 })
503 .collect::<Result<_, _>>()?,
504 ),
505 Self::String(_) => Self::make_list_string(
506 elements
507 .into_iter()
508 .map(|e| match e {
509 Self::String(s) => Ok(s),
510 _ => Err(crate::error::ExpressionError::type_error(format!(
511 "make_list expected string element, got {}",
512 e.type_name()
513 ))),
514 })
515 .collect::<Result<_, _>>()?,
516 ),
517 Self::Path { format, .. } => {
518 let fmt = *format;
519 Self::make_list_path(
520 elements
521 .into_iter()
522 .map(|e| match e {
523 Self::Path { value, .. } => Ok(value),
524 Self::String(value) => Ok(value),
525 _ => Err(crate::error::ExpressionError::type_error(format!(
526 "make_list expected path element, got {}",
527 e.type_name()
528 ))),
529 })
530 .collect::<Result<_, _>>()?,
531 fmt,
532 )
533 }
534 _ if elements[0].is_list() => Self::make_list_list(elements, ExprType::NULLTYPE),
535 Self::RangeExpr(_) => Self::make_list_list(elements, ExprType::RANGE_EXPR),
536 _ => {
537 return Err(crate::error::ExpressionError::type_error(format!(
538 "Cannot create list from {} elements",
539 elements[0].type_name()
540 )))
541 }
542 })
543 }
544
545 pub fn unresolved(constraint: ExprType) -> Self {
547 Self::Unresolved(constraint)
548 }
549 pub fn is_unresolved(&self) -> bool {
551 matches!(self, Self::Unresolved(_))
552 }
553
554 pub fn new_path(value: impl Into<String>, format: PathFormat) -> Self {
564 let value = value.into();
565 let normalized = normalize_path_separators(&value, format);
566 Self::Path {
567 value: normalized,
568 format,
569 }
570 }
571
572 pub fn from_str_coerce(
574 s: &str,
575 target: &ExprType,
576 path_format: PathFormat,
577 ) -> Result<Self, String> {
578 match target.code() {
579 TypeCode::Int => s
580 .parse::<i64>()
581 .map(ExprValue::Int)
582 .map_err(|e| format!("Cannot convert '{s}' to int: {e}")),
583 TypeCode::Float => {
584 let v: f64 = s
585 .parse()
586 .map_err(|e| format!("Cannot convert '{s}' to float: {e}"))?;
587 if v.is_infinite() || v.is_nan() {
588 return Err(format!("Cannot convert '{s}' to float"));
589 }
590 Ok(ExprValue::Float(
591 Float64::with_str(v, s.to_string()).map_err(|e| e.to_string())?,
592 ))
593 }
594 TypeCode::Bool => match s.to_lowercase().as_str() {
595 "true" | "yes" | "on" | "1" => Ok(ExprValue::Bool(true)),
596 "false" | "no" | "off" | "0" => Ok(ExprValue::Bool(false)),
597 _ => Err(format!("Cannot convert '{s}' to bool")),
598 },
599 TypeCode::String => Ok(ExprValue::String(s.to_string())),
600 TypeCode::Path => Ok(ExprValue::new_path(s, path_format)),
601 TypeCode::RangeExpr => {
602 let r: crate::range_expr::RangeExpr =
603 s.parse().map_err(|e: crate::error::ExpressionError| {
604 format!("Cannot convert '{s}' to range_expr: {e}")
605 })?;
606 Ok(ExprValue::RangeExpr(r))
607 }
608 TypeCode::NullType if s == "null" => Ok(ExprValue::Null),
609 _ => Err(format!("Cannot coerce string to {target}")),
610 }
611 }
612
613 pub fn coerce(self, target: &ExprType, path_format: PathFormat) -> Result<Self, String> {
615 if self.expr_type() == *target {
616 return Ok(self);
617 }
618 match (&self, target.code()) {
619 (ExprValue::Int(i), TypeCode::Float) => {
620 Ok(ExprValue::Float(Float64::new(*i as f64).unwrap()))
621 }
622 (ExprValue::Float(f), TypeCode::Int) => {
623 let v = f.value();
624 if v.fract() == 0.0 && v.is_finite() {
625 Ok(ExprValue::Int(v as i64))
626 } else {
627 Err(format!(
628 "Cannot coerce float to int: {} is not a whole number",
629 f.to_display_string()
630 ))
631 }
632 }
633 (ExprValue::Bool(b), TypeCode::String) => Ok(ExprValue::String(
634 if *b { "true" } else { "false" }.to_string(),
635 )),
636 (ExprValue::Int(i), TypeCode::String) => Ok(ExprValue::String(i.to_string())),
637 (ExprValue::Float(f), TypeCode::String) => Ok(ExprValue::String(f.to_display_string())),
638 (ExprValue::String(s), _) => ExprValue::from_str_coerce(s, target, path_format),
639 (ExprValue::Path { value, .. }, TypeCode::String) => {
640 Ok(ExprValue::String(value.clone()))
641 }
642 (ExprValue::RangeExpr(r), TypeCode::String) => Ok(ExprValue::String(r.to_string())),
643 (ExprValue::RangeExpr(r), TypeCode::List) => Ok(ExprValue::ListInt(r.to_vec())),
644 _ if target.code() == TypeCode::List && target.params().len() == 1 => {
645 let elem_type = &target.params()[0];
646 if let Some(elements) = self.list_elements() {
647 let coerced: Result<Vec<_>, _> = elements
648 .into_iter()
649 .map(|e| e.coerce(elem_type, path_format))
650 .collect();
651 Ok(ExprValue::make_list(coerced?, elem_type.clone())
652 .map_err(|e| e.to_string())?)
653 } else {
654 Err(format!("Cannot coerce {} to {target}", self.expr_type()))
655 }
656 }
657 _ => Err(format!("Cannot coerce {} to {target}", self.expr_type())),
658 }
659 }
660
661 pub fn repr_python(&self) -> String {
663 match self {
664 Self::Null => "ExprValue(None)".to_string(),
665 Self::Bool(b) => format!("ExprValue({})", if *b { "True" } else { "False" }),
666 Self::Int(i) => format!("ExprValue({i})"),
667 Self::Float(f) => {
668 if f.original.is_some() {
669 format!("ExprValue('{}', type='float')", f.to_display_string())
670 } else {
671 format!("ExprValue({})", f.to_display_string())
672 }
673 }
674 Self::String(s) => format!("ExprValue('{s}')"),
675 Self::Path { value, format } => {
676 format!(
677 "ExprValue('{value}', type='path', path_format=PathFormat.{})",
678 match format {
679 PathFormat::Posix => "POSIX",
680 PathFormat::Windows => "WINDOWS",
681 PathFormat::Uri => "URI",
682 }
683 )
684 }
685 Self::RangeExpr(r) => format!("ExprValue('{}', type='range_expr')", r),
686 Self::Unresolved(t) => format!("ExprValue.unresolved(ExprType(\"{t}\"))"),
687 val if val.is_list() => {
688 let type_str = val.expr_type().to_string();
689 let pf = val.find_path_format();
691 let pf_str = pf
692 .map(|f| {
693 format!(
694 ", path_format=PathFormat.{}",
695 match f {
696 PathFormat::Posix => "POSIX",
697 PathFormat::Windows => "WINDOWS",
698 PathFormat::Uri => "URI",
699 }
700 )
701 })
702 .unwrap_or_default();
703 format!(
704 "ExprValue({}, type='{type_str}'{pf_str})",
705 val.repr_python_list()
706 )
707 }
708 _ => format!("ExprValue('{}')", self.to_display_string()),
709 }
710 }
711
712 fn repr_python_list(&self) -> String {
713 let elements = self.list_elements().unwrap_or_default();
714 let items: Vec<String> = elements
715 .iter()
716 .map(|e| {
717 if e.is_list() {
718 e.repr_python_list()
719 } else {
720 match e {
721 ExprValue::String(s) | ExprValue::Path { value: s, .. } => format!("'{s}'"),
722 ExprValue::Bool(b) => if *b { "True" } else { "False" }.to_string(),
723 ExprValue::Int(i) => i.to_string(),
724 ExprValue::Float(f) => f.to_display_string(),
725 _ => e.to_display_string(),
726 }
727 }
728 })
729 .collect();
730 format!("[{}]", items.join(", "))
731 }
732
733 fn find_path_format(&self) -> Option<PathFormat> {
734 match self {
735 Self::ListPath(_, fmt, _) => Some(*fmt),
736 Self::ListList(v, _, _) => v.first().and_then(|e| e.find_path_format()),
737 _ => None,
738 }
739 }
740
741 pub fn to_json_transport(&self) -> serde_json::Value {
745 let type_str = self.expr_type().to_string();
746 let value = self.transport_value();
747 serde_json::json!({"type": type_str, "value": value})
748 }
749
750 pub fn transport_value(&self) -> serde_json::Value {
751 match self {
752 val if val.is_list() => {
753 let elements = val.list_elements().unwrap_or_default();
754 serde_json::Value::Array(elements.iter().map(|e| e.transport_value()).collect())
755 }
756 _ => serde_json::Value::String(self.to_display_string()),
757 }
758 }
759
760 pub fn from_json_transport(
763 json: &serde_json::Value,
764 path_format: PathFormat,
765 ) -> Result<Self, String> {
766 let type_str = json
767 .get("type")
768 .and_then(|v| v.as_str())
769 .ok_or("Missing 'type' field")?;
770 let value = json.get("value").ok_or("Missing 'value' field")?;
771 let expr_type = ExprType::parse(type_str)?;
772 Self::from_transport_value(value, &expr_type, path_format)
773 }
774
775 pub fn from_transport_value(
776 value: &serde_json::Value,
777 target: &ExprType,
778 path_format: PathFormat,
779 ) -> Result<Self, String> {
780 Self::from_transport_value_inner(value, target, path_format, 0)
781 }
782
783 fn from_transport_value_inner(
784 value: &serde_json::Value,
785 target: &ExprType,
786 path_format: PathFormat,
787 depth: usize,
788 ) -> Result<Self, String> {
789 if depth > 10 {
790 return Err("Transport value nesting depth exceeded".to_string());
791 }
792 if target.code() == TypeCode::List {
793 let elem_type = target
794 .params()
795 .first()
796 .ok_or("List type missing element type")?;
797 let arr = value.as_array().ok_or("Expected array for list type")?;
798 let elements: Result<Vec<_>, _> = arr
799 .iter()
800 .map(|v| Self::from_transport_value_inner(v, elem_type, path_format, depth + 1))
801 .collect();
802 return ExprValue::make_list(elements?, elem_type.clone()).map_err(|e| e.to_string());
803 }
804 let s = value
805 .as_str()
806 .ok_or_else(|| format!("Expected string value for {target}"))?;
807 ExprValue::from_str_coerce(s, target, path_format)
808 }
809
810 pub fn is_list(&self) -> bool {
812 matches!(
813 self,
814 Self::ListBool(_)
815 | Self::ListInt(_)
816 | Self::ListFloat(_)
817 | Self::ListString(_, _)
818 | Self::ListPath(_, _, _)
819 | Self::ListList(_, _, _)
820 )
821 }
822
823 pub fn list_len(&self) -> Option<usize> {
825 match self {
826 Self::ListBool(v) => Some(v.len()),
827 Self::ListInt(v) => Some(v.len()),
828 Self::ListFloat(v) => Some(v.len()),
829 Self::ListString(v, _) => Some(v.len()),
830 Self::ListPath(v, _, _) => Some(v.len()),
831 Self::ListList(v, _, _) => Some(v.len()),
832 _ => None,
833 }
834 }
835
836 pub fn list_elements(&self) -> Option<Vec<ExprValue>> {
838 match self {
839 Self::ListBool(v) => Some(v.iter().map(|b| ExprValue::Bool(*b)).collect()),
840 Self::ListInt(v) => Some(v.iter().map(|i| ExprValue::Int(*i)).collect()),
841 Self::ListFloat(v) => Some(v.iter().map(|f| ExprValue::Float(f.clone())).collect()),
842 Self::ListString(v, _) => {
843 Some(v.iter().map(|s| ExprValue::String(s.clone())).collect())
844 }
845 Self::ListPath(v, fmt, _) => Some(
846 v.iter()
847 .map(|s| ExprValue::new_path(s.clone(), *fmt))
848 .collect(),
849 ),
850 Self::ListList(v, _, _) => Some(v.clone()),
851 _ => None,
852 }
853 }
854
855 pub fn list_iter(&self) -> Option<ListIter<'_>> {
858 match self {
859 Self::ListBool(v) => Some(ListIter::Bool(v.iter())),
860 Self::ListInt(v) => Some(ListIter::Int(v.iter())),
861 Self::ListFloat(v) => Some(ListIter::Float(v.iter())),
862 Self::ListString(v, _) => Some(ListIter::String(v.iter())),
863 Self::ListPath(v, fmt, _) => Some(ListIter::Path(v.iter(), *fmt)),
864 Self::ListList(v, _, _) => Some(ListIter::List(v.iter())),
865 _ => None,
866 }
867 }
868
869 pub fn list_get(&self, index: i64) -> Option<ExprValue> {
872 let len = self.list_len()? as i64;
873 let i = if index < 0 { len + index } else { index };
874 if i < 0 || i >= len {
875 return None;
876 }
877 let i = i as usize;
878 match self {
879 Self::ListBool(v) => Some(ExprValue::Bool(v[i])),
880 Self::ListInt(v) => Some(ExprValue::Int(v[i])),
881 Self::ListFloat(v) => Some(ExprValue::Float(v[i].clone())),
882 Self::ListString(v, _) => Some(ExprValue::String(v[i].clone())),
883 Self::ListPath(v, fmt, _) => Some(ExprValue::new_path(v[i].clone(), *fmt)),
884 Self::ListList(v, _, _) => Some(v[i].clone()),
885 _ => None,
886 }
887 }
888
889 pub fn list_elem_type(&self) -> Option<ExprType> {
898 match self {
899 Self::ListBool(_) => Some(ExprType::BOOL),
900 Self::ListInt(_) => Some(ExprType::INT),
901 Self::ListFloat(_) => Some(ExprType::FLOAT),
902 Self::ListString(_, _) => Some(ExprType::STRING),
903 Self::ListPath(_, _, _) => Some(ExprType::PATH),
904 Self::ListList(_, elem_type, _) => Some(elem_type.clone()),
905 _ => None,
906 }
907 }
908
909 pub fn into_list(self) -> Option<(Vec<ExprValue>, ExprType)> {
911 let et = self.list_elem_type()?;
912 Some((self.list_elements()?, et))
913 }
914
915 pub fn expr_type(&self) -> ExprType {
917 match self {
918 Self::Null => ExprType::NULLTYPE,
919 Self::Bool(_) => ExprType::BOOL,
920 Self::Int(_) => ExprType::INT,
921 Self::Float(_) => ExprType::FLOAT,
922 Self::String(_) => ExprType::STRING,
923 Self::Path { .. } => ExprType::PATH,
924 Self::ListBool(_) => ExprType::list(ExprType::BOOL),
925 Self::ListInt(_) => ExprType::list(ExprType::INT),
926 Self::ListFloat(_) => ExprType::list(ExprType::FLOAT),
927 Self::ListString(_, _) => ExprType::list(ExprType::STRING),
928 Self::ListPath(_, _, _) => ExprType::list(ExprType::PATH),
929 Self::ListList(_, elem_type, _) => ExprType::list(elem_type.clone()),
930 Self::RangeExpr(_) => ExprType::RANGE_EXPR,
931 Self::Unresolved(t) => ExprType::unresolved(t.clone()),
932 }
933 }
934
935 pub fn as_str_repr(&self) -> std::borrow::Cow<'_, str> {
938 match self {
939 Self::String(s) => std::borrow::Cow::Borrowed(s),
940 Self::Path { value, .. } => std::borrow::Cow::Borrowed(value),
941 _ => std::borrow::Cow::Owned(self.to_display_string()),
942 }
943 }
944
945 pub fn type_name(&self) -> &'static str {
947 match self {
948 Self::Null => "null",
949 Self::Bool(_) => "bool",
950 Self::Int(_) => "int",
951 Self::Float(_) => "float",
952 Self::String(_) => "string",
953 Self::Path { .. } => "path",
954 Self::RangeExpr(_) => "range_expr",
955 Self::Unresolved(_) => "unresolved",
956 _ if self.is_list() => "list",
957 _ => "unknown",
958 }
959 }
960
961 pub fn to_display_string(&self) -> String {
963 match self {
964 Self::Null => "null".to_string(),
965 Self::Bool(b) => if *b { "true" } else { "false" }.to_string(),
966 Self::Int(i) => i.to_string(),
967 Self::Float(fv) => fv.to_display_string(),
968 Self::String(s) => s.clone(),
969 Self::Path { value, .. } => value.clone(),
970 Self::ListBool(v) => format!(
971 "[{}]",
972 v.iter()
973 .map(|b| if *b { "true" } else { "false" })
974 .collect::<Vec<_>>()
975 .join(", ")
976 ),
977 Self::ListInt(v) => format!(
978 "[{}]",
979 v.iter()
980 .map(|i| i.to_string())
981 .collect::<Vec<_>>()
982 .join(", ")
983 ),
984 Self::ListFloat(v) => format!(
985 "[{}]",
986 v.iter()
987 .map(|f| f.to_display_string())
988 .collect::<Vec<_>>()
989 .join(", ")
990 ),
991 Self::ListString(v, _) => format!(
992 "[{}]",
993 v.iter()
994 .map(|s| format!("\"{}\"", s))
995 .collect::<Vec<_>>()
996 .join(", ")
997 ),
998 Self::ListPath(v, _, _) => format!(
999 "[{}]",
1000 v.iter()
1001 .map(|s| format!("\"{}\"", s))
1002 .collect::<Vec<_>>()
1003 .join(", ")
1004 ),
1005 Self::ListList(v, _, _) => format!(
1006 "[{}]",
1007 v.iter()
1008 .map(|e| e.to_display_string())
1009 .collect::<Vec<_>>()
1010 .join(", ")
1011 ),
1012 Self::RangeExpr(r) => r.to_string(),
1013 Self::Unresolved(t) => format!("<unresolved[{t}]>"),
1014 }
1015 }
1016
1017 pub fn memory_size(&self) -> usize {
1019 std::mem::size_of::<ExprValue>() + self.heap_size()
1020 }
1021
1022 fn heap_size(&self) -> usize {
1024 use std::mem::size_of;
1025 match self {
1026 Self::Null | Self::Bool(_) | Self::Int(_) | Self::Unresolved(_) => 0,
1027 Self::Float(f) => f.original.as_ref().map_or(0, |s| s.len()),
1028 Self::String(s) | Self::Path { value: s, .. } => s.capacity(),
1029 Self::ListBool(v) => v.capacity(),
1030 Self::ListInt(v) => v.capacity() * size_of::<i64>(),
1031 Self::ListFloat(v) => v.capacity() * size_of::<Float64>(),
1032 Self::ListString(_, cached) | Self::ListPath(_, _, cached) => *cached,
1033 Self::ListList(_, _, cached) => *cached,
1034 Self::RangeExpr(r) => r.heap_size(),
1035 }
1036 }
1037
1038 pub fn equals(&self, other: &ExprValue) -> bool {
1040 match (self, other) {
1041 (Self::Null, Self::Null) => true,
1042 (Self::Bool(a), Self::Bool(b)) => a == b,
1043 (Self::Int(a), Self::Int(b)) => a == b,
1044 (Self::Float(a), Self::Float(b)) => a.value == b.value,
1045 (Self::Int(a), Self::Float(b)) => (*a as f64) == b.value,
1046 (Self::Float(a), Self::Int(b)) => a.value == (*b as f64),
1047 (Self::String(a), Self::String(b)) => a == b,
1048 (Self::Path { value: a, .. }, Self::Path { value: b, .. }) => a == b,
1049 (Self::String(a), Self::Path { value: b, .. })
1050 | (Self::Path { value: b, .. }, Self::String(a)) => a == b,
1051 _ if self.is_list() && other.is_list() => {
1052 let (a_iter, b_iter) = match (self.list_iter(), other.list_iter()) {
1053 (Some(a), Some(b)) => (a, b),
1054 _ => return false,
1055 };
1056 let (a_len, b_len) = (a_iter.len(), b_iter.len());
1057 if a_len != b_len {
1058 return false;
1059 }
1060 a_iter.zip(b_iter).all(|(x, y)| x.equals(&y))
1061 }
1062 (Self::ListInt(elems), Self::RangeExpr(r))
1063 | (Self::RangeExpr(r), Self::ListInt(elems)) => {
1064 let rv: Vec<i64> = r.iter().collect();
1065 elems.len() == rv.len() && elems.iter().zip(rv.iter()).all(|(a, b)| a == b)
1066 }
1067 (Self::RangeExpr(a), Self::RangeExpr(b)) => a == b,
1068 (Self::Unresolved(a), Self::Unresolved(b)) => a == b,
1069 _ => false,
1070 }
1071 }
1072
1073 pub fn compare(
1075 &self,
1076 other: &ExprValue,
1077 ) -> Result<std::cmp::Ordering, crate::error::ExpressionError> {
1078 match (self, other) {
1079 (Self::Int(a), Self::Int(b)) => Ok(a.cmp(b)),
1080 (Self::Float(a), Self::Float(b)) => a
1081 .value
1082 .partial_cmp(&b.value)
1083 .ok_or_else(|| crate::error::ExpressionError::new("Cannot compare NaN")),
1084 (Self::Int(a), Self::Float(b)) => (*a as f64)
1085 .partial_cmp(&b.value)
1086 .ok_or_else(|| crate::error::ExpressionError::new("Cannot compare NaN")),
1087 (Self::Float(a), Self::Int(b)) => a
1088 .value
1089 .partial_cmp(&(*b as f64))
1090 .ok_or_else(|| crate::error::ExpressionError::new("Cannot compare NaN")),
1091 (Self::Bool(a), Self::Bool(b)) => Ok(a.cmp(b)),
1092 (Self::String(a), Self::String(b)) => Ok(a.cmp(b)),
1093 (Self::Path { value: a, .. }, Self::Path { value: b, .. }) => Ok(a.cmp(b)),
1094 (Self::String(a), Self::Path { value: b, .. })
1095 | (Self::Path { value: b, .. }, Self::String(a)) => Ok(a.cmp(b)),
1096 _ if self.is_list() && other.is_list() => {
1097 let (a_iter, b_iter) = match (self.list_iter(), other.list_iter()) {
1098 (Some(a), Some(b)) => (a, b),
1099 _ => {
1100 return Err(crate::error::ExpressionError::new(format!(
1101 "Cannot compare {} and {}",
1102 self.expr_type(),
1103 other.expr_type()
1104 )))
1105 }
1106 };
1107 let (a_len, b_len) = (a_iter.len(), b_iter.len());
1108 for (x, y) in a_iter.zip(b_iter) {
1109 match x.compare(&y) {
1110 Ok(std::cmp::Ordering::Equal) => continue,
1111 other => return other,
1112 }
1113 }
1114 Ok(a_len.cmp(&b_len))
1115 }
1116 _ => Err(crate::error::ExpressionError::new(format!(
1117 "Cannot compare {} and {}",
1118 self.expr_type(),
1119 other.expr_type()
1120 ))),
1121 }
1122 }
1123}
1124
1125impl PartialEq for ExprValue {
1126 fn eq(&self, other: &Self) -> bool {
1127 self.equals(other)
1128 }
1129}
1130
1131impl From<bool> for ExprValue {
1132 fn from(v: bool) -> Self {
1133 Self::Bool(v)
1134 }
1135}
1136impl From<i32> for ExprValue {
1137 fn from(v: i32) -> Self {
1138 Self::Int(v as i64)
1139 }
1140}
1141impl From<i64> for ExprValue {
1142 fn from(v: i64) -> Self {
1143 Self::Int(v)
1144 }
1145}
1146impl From<String> for ExprValue {
1147 fn from(v: String) -> Self {
1148 Self::String(v)
1149 }
1150}
1151impl From<&str> for ExprValue {
1152 fn from(v: &str) -> Self {
1153 Self::String(v.to_string())
1154 }
1155}
1156impl From<RangeExpr> for ExprValue {
1157 fn from(v: RangeExpr) -> Self {
1158 Self::RangeExpr(v)
1159 }
1160}
1161impl From<crate::types::ExprType> for ExprValue {
1162 fn from(t: crate::types::ExprType) -> Self {
1163 Self::Unresolved(t)
1164 }
1165}
1166
1167pub enum ListIter<'a> {
1169 Bool(std::slice::Iter<'a, bool>),
1170 Int(std::slice::Iter<'a, i64>),
1171 Float(std::slice::Iter<'a, Float64>),
1172 String(std::slice::Iter<'a, String>),
1173 Path(std::slice::Iter<'a, String>, PathFormat),
1174 List(std::slice::Iter<'a, ExprValue>),
1175}
1176
1177impl<'a> Iterator for ListIter<'a> {
1178 type Item = ExprValue;
1179 fn next(&mut self) -> Option<ExprValue> {
1180 match self {
1181 Self::Bool(it) => it.next().map(|b| ExprValue::Bool(*b)),
1182 Self::Int(it) => it.next().map(|i| ExprValue::Int(*i)),
1183 Self::Float(it) => it.next().map(|f| ExprValue::Float(f.clone())),
1184 Self::String(it) => it.next().map(|s| ExprValue::String(s.clone())),
1185 Self::Path(it, fmt) => it.next().map(|s| ExprValue::new_path(s.clone(), *fmt)),
1186 Self::List(it) => it.next().cloned(),
1187 }
1188 }
1189 fn size_hint(&self) -> (usize, Option<usize>) {
1190 match self {
1191 Self::Bool(it) => it.size_hint(),
1192 Self::Int(it) => it.size_hint(),
1193 Self::Float(it) => it.size_hint(),
1194 Self::String(it) => it.size_hint(),
1195 Self::Path(it, _) => it.size_hint(),
1196 Self::List(it) => it.size_hint(),
1197 }
1198 }
1199}
1200
1201impl<'a> ExactSizeIterator for ListIter<'a> {}
1202
1203pub fn format_float(f: f64) -> String {
1204 if f == 0.0 {
1205 return "0.0".to_string();
1206 }
1207 let abs = f.abs();
1208 if !(1e-4..1e16).contains(&abs) {
1209 format!("{:e}", f)
1210 .replace("e-0", "e-")
1211 .replace("e0", "e+0")
1212 .replace("e", "e+")
1213 .replace("e+-", "e-")
1214 .replace("e++", "e+")
1215 } else if f.fract() == 0.0 {
1216 format!("{}.0", f as i64)
1217 } else {
1218 f.to_string()
1219 }
1220}
1221
1222#[must_use]
1228pub fn normalize_path_separators(value: &str, format: PathFormat) -> String {
1229 if crate::uri_path::is_uri(value) {
1230 return value.to_string();
1231 }
1232 match format {
1233 PathFormat::Windows => value.replace('/', "\\"),
1234 PathFormat::Posix | PathFormat::Uri => value.to_string(),
1235 }
1236}