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> {
632 if self.expr_type() == *target {
636 return Ok(self);
637 }
638 if target.code() == TypeCode::Union && target.match_type(&self.expr_type()).is_some() {
639 return Ok(self);
640 }
641 if target.code() == TypeCode::Union {
647 for member in target.params() {
648 if matches!(
649 member.code(),
650 TypeCode::NullType | TypeCode::List | TypeCode::Union
651 ) {
652 continue;
653 }
654 if let Ok(coerced) = self.clone().coerce(member, path_format) {
655 return Ok(coerced);
656 }
657 }
658 return Err(format!("Cannot coerce {} to {target}", self.expr_type()));
659 }
660 match (&self, target.code()) {
661 (ExprValue::Int(i), TypeCode::Float) => {
662 Ok(ExprValue::Float(Float64::new(*i as f64).unwrap()))
663 }
664 (ExprValue::Float(f), TypeCode::Int) => {
665 let v = f.value();
666 if v.fract() == 0.0 && v.is_finite() {
667 Ok(ExprValue::Int(v as i64))
668 } else {
669 Err(format!(
670 "Cannot coerce float to int: {} is not a whole number",
671 f.to_display_string()
672 ))
673 }
674 }
675 (ExprValue::Bool(b), TypeCode::String) => Ok(ExprValue::String(
676 if *b { "true" } else { "false" }.to_string(),
677 )),
678 (ExprValue::Int(i), TypeCode::String) => Ok(ExprValue::String(i.to_string())),
679 (ExprValue::Float(f), TypeCode::String) => Ok(ExprValue::String(f.to_display_string())),
680 (ExprValue::String(s), _) => ExprValue::from_str_coerce(s, target, path_format),
681 (ExprValue::Path { value, .. }, TypeCode::String) => {
682 Ok(ExprValue::String(value.clone()))
683 }
684 (ExprValue::RangeExpr(r), TypeCode::String) => Ok(ExprValue::String(r.to_string())),
685 (ExprValue::RangeExpr(r), TypeCode::List) => Ok(ExprValue::ListInt(r.to_vec())),
686 _ if target.code() == TypeCode::List && target.params().len() == 1 => {
687 let elem_type = &target.params()[0];
688 if let Some(elements) = self.list_elements() {
689 let coerced: Result<Vec<_>, _> = elements
690 .into_iter()
691 .map(|e| e.coerce(elem_type, path_format))
692 .collect();
693 Ok(ExprValue::make_list(coerced?, elem_type.clone())
694 .map_err(|e| e.to_string())?)
695 } else {
696 Err(format!("Cannot coerce {} to {target}", self.expr_type()))
697 }
698 }
699 _ => Err(format!("Cannot coerce {} to {target}", self.expr_type())),
700 }
701 }
702
703 pub fn repr_python(&self) -> String {
705 match self {
706 Self::Null => "ExprValue(None)".to_string(),
707 Self::Bool(b) => format!("ExprValue({})", if *b { "True" } else { "False" }),
708 Self::Int(i) => format!("ExprValue({i})"),
709 Self::Float(f) => {
710 if f.original.is_some() {
711 format!("ExprValue('{}', type='float')", f.to_display_string())
712 } else {
713 format!("ExprValue({})", f.to_display_string())
714 }
715 }
716 Self::String(s) => format!("ExprValue('{s}')"),
717 Self::Path { value, format } => {
718 format!(
719 "ExprValue('{value}', type='path', path_format=PathFormat.{})",
720 match format {
721 PathFormat::Posix => "POSIX",
722 PathFormat::Windows => "WINDOWS",
723 PathFormat::Uri => "URI",
724 }
725 )
726 }
727 Self::RangeExpr(r) => format!("ExprValue('{}', type='range_expr')", r),
728 Self::Unresolved(t) => format!("ExprValue.unresolved(ExprType(\"{t}\"))"),
729 val if val.is_list() => {
730 let type_str = val.expr_type().to_string();
731 let pf = val.find_path_format();
733 let pf_str = pf
734 .map(|f| {
735 format!(
736 ", path_format=PathFormat.{}",
737 match f {
738 PathFormat::Posix => "POSIX",
739 PathFormat::Windows => "WINDOWS",
740 PathFormat::Uri => "URI",
741 }
742 )
743 })
744 .unwrap_or_default();
745 format!(
746 "ExprValue({}, type='{type_str}'{pf_str})",
747 val.repr_python_list()
748 )
749 }
750 _ => format!("ExprValue('{}')", self.to_display_string()),
751 }
752 }
753
754 fn repr_python_list(&self) -> String {
755 let elements = self.list_elements().unwrap_or_default();
756 let items: Vec<String> = elements
757 .iter()
758 .map(|e| {
759 if e.is_list() {
760 e.repr_python_list()
761 } else {
762 match e {
763 ExprValue::String(s) | ExprValue::Path { value: s, .. } => format!("'{s}'"),
764 ExprValue::Bool(b) => if *b { "True" } else { "False" }.to_string(),
765 ExprValue::Int(i) => i.to_string(),
766 ExprValue::Float(f) => f.to_display_string(),
767 _ => e.to_display_string(),
768 }
769 }
770 })
771 .collect();
772 format!("[{}]", items.join(", "))
773 }
774
775 fn find_path_format(&self) -> Option<PathFormat> {
776 match self {
777 Self::ListPath(_, fmt, _) => Some(*fmt),
778 Self::ListList(v, _, _) => v.first().and_then(|e| e.find_path_format()),
779 _ => None,
780 }
781 }
782
783 pub fn to_json_transport(&self) -> serde_json::Value {
787 let type_str = self.expr_type().to_string();
788 let value = self.transport_value();
789 serde_json::json!({"type": type_str, "value": value})
790 }
791
792 pub fn transport_value(&self) -> serde_json::Value {
793 match self {
794 val if val.is_list() => {
795 let elements = val.list_elements().unwrap_or_default();
796 serde_json::Value::Array(elements.iter().map(|e| e.transport_value()).collect())
797 }
798 _ => serde_json::Value::String(self.to_display_string()),
799 }
800 }
801
802 pub fn from_json_transport(
805 json: &serde_json::Value,
806 path_format: PathFormat,
807 ) -> Result<Self, String> {
808 let type_str = json
809 .get("type")
810 .and_then(|v| v.as_str())
811 .ok_or("Missing 'type' field")?;
812 let value = json.get("value").ok_or("Missing 'value' field")?;
813 let expr_type = ExprType::parse(type_str)?;
814 Self::from_transport_value(value, &expr_type, path_format)
815 }
816
817 pub fn from_transport_value(
818 value: &serde_json::Value,
819 target: &ExprType,
820 path_format: PathFormat,
821 ) -> Result<Self, String> {
822 Self::from_transport_value_inner(value, target, path_format, 0)
823 }
824
825 fn from_transport_value_inner(
826 value: &serde_json::Value,
827 target: &ExprType,
828 path_format: PathFormat,
829 depth: usize,
830 ) -> Result<Self, String> {
831 if depth > 10 {
832 return Err("Transport value nesting depth exceeded".to_string());
833 }
834 if target.code() == TypeCode::List {
835 let elem_type = target
836 .params()
837 .first()
838 .ok_or("List type missing element type")?;
839 let arr = value.as_array().ok_or("Expected array for list type")?;
840 let elements: Result<Vec<_>, _> = arr
841 .iter()
842 .map(|v| Self::from_transport_value_inner(v, elem_type, path_format, depth + 1))
843 .collect();
844 return ExprValue::make_list(elements?, elem_type.clone()).map_err(|e| e.to_string());
845 }
846 let s = value
847 .as_str()
848 .ok_or_else(|| format!("Expected string value for {target}"))?;
849 ExprValue::from_str_coerce(s, target, path_format)
850 }
851
852 pub fn is_list(&self) -> bool {
854 matches!(
855 self,
856 Self::ListBool(_)
857 | Self::ListInt(_)
858 | Self::ListFloat(_)
859 | Self::ListString(_, _)
860 | Self::ListPath(_, _, _)
861 | Self::ListList(_, _, _)
862 )
863 }
864
865 pub fn list_len(&self) -> Option<usize> {
867 match self {
868 Self::ListBool(v) => Some(v.len()),
869 Self::ListInt(v) => Some(v.len()),
870 Self::ListFloat(v) => Some(v.len()),
871 Self::ListString(v, _) => Some(v.len()),
872 Self::ListPath(v, _, _) => Some(v.len()),
873 Self::ListList(v, _, _) => Some(v.len()),
874 _ => None,
875 }
876 }
877
878 pub fn list_elements(&self) -> Option<Vec<ExprValue>> {
880 match self {
881 Self::ListBool(v) => Some(v.iter().map(|b| ExprValue::Bool(*b)).collect()),
882 Self::ListInt(v) => Some(v.iter().map(|i| ExprValue::Int(*i)).collect()),
883 Self::ListFloat(v) => Some(v.iter().map(|f| ExprValue::Float(f.clone())).collect()),
884 Self::ListString(v, _) => {
885 Some(v.iter().map(|s| ExprValue::String(s.clone())).collect())
886 }
887 Self::ListPath(v, fmt, _) => Some(
888 v.iter()
889 .map(|s| ExprValue::new_path(s.clone(), *fmt))
890 .collect(),
891 ),
892 Self::ListList(v, _, _) => Some(v.clone()),
893 _ => None,
894 }
895 }
896
897 pub fn list_iter(&self) -> Option<ListIter<'_>> {
900 match self {
901 Self::ListBool(v) => Some(ListIter::Bool(v.iter())),
902 Self::ListInt(v) => Some(ListIter::Int(v.iter())),
903 Self::ListFloat(v) => Some(ListIter::Float(v.iter())),
904 Self::ListString(v, _) => Some(ListIter::String(v.iter())),
905 Self::ListPath(v, fmt, _) => Some(ListIter::Path(v.iter(), *fmt)),
906 Self::ListList(v, _, _) => Some(ListIter::List(v.iter())),
907 _ => None,
908 }
909 }
910
911 pub fn list_get(&self, index: i64) -> Option<ExprValue> {
914 let len = self.list_len()? as i64;
915 let i = if index < 0 { len + index } else { index };
916 if i < 0 || i >= len {
917 return None;
918 }
919 let i = i as usize;
920 match self {
921 Self::ListBool(v) => Some(ExprValue::Bool(v[i])),
922 Self::ListInt(v) => Some(ExprValue::Int(v[i])),
923 Self::ListFloat(v) => Some(ExprValue::Float(v[i].clone())),
924 Self::ListString(v, _) => Some(ExprValue::String(v[i].clone())),
925 Self::ListPath(v, fmt, _) => Some(ExprValue::new_path(v[i].clone(), *fmt)),
926 Self::ListList(v, _, _) => Some(v[i].clone()),
927 _ => None,
928 }
929 }
930
931 pub fn list_elem_type(&self) -> Option<ExprType> {
940 match self {
941 Self::ListBool(_) => Some(ExprType::BOOL),
942 Self::ListInt(_) => Some(ExprType::INT),
943 Self::ListFloat(_) => Some(ExprType::FLOAT),
944 Self::ListString(_, _) => Some(ExprType::STRING),
945 Self::ListPath(_, _, _) => Some(ExprType::PATH),
946 Self::ListList(_, elem_type, _) => Some(elem_type.clone()),
947 _ => None,
948 }
949 }
950
951 pub fn into_list(self) -> Option<(Vec<ExprValue>, ExprType)> {
953 let et = self.list_elem_type()?;
954 Some((self.list_elements()?, et))
955 }
956
957 pub fn expr_type(&self) -> ExprType {
959 match self {
960 Self::Null => ExprType::NULLTYPE,
961 Self::Bool(_) => ExprType::BOOL,
962 Self::Int(_) => ExprType::INT,
963 Self::Float(_) => ExprType::FLOAT,
964 Self::String(_) => ExprType::STRING,
965 Self::Path { .. } => ExprType::PATH,
966 Self::ListBool(_) => ExprType::list(ExprType::BOOL),
967 Self::ListInt(_) => ExprType::list(ExprType::INT),
968 Self::ListFloat(_) => ExprType::list(ExprType::FLOAT),
969 Self::ListString(_, _) => ExprType::list(ExprType::STRING),
970 Self::ListPath(_, _, _) => ExprType::list(ExprType::PATH),
971 Self::ListList(_, elem_type, _) => ExprType::list(elem_type.clone()),
972 Self::RangeExpr(_) => ExprType::RANGE_EXPR,
973 Self::Unresolved(t) => ExprType::unresolved(t.clone()),
974 }
975 }
976
977 pub fn as_str_repr(&self) -> std::borrow::Cow<'_, str> {
980 match self {
981 Self::String(s) => std::borrow::Cow::Borrowed(s),
982 Self::Path { value, .. } => std::borrow::Cow::Borrowed(value),
983 _ => std::borrow::Cow::Owned(self.to_display_string()),
984 }
985 }
986
987 pub fn type_name(&self) -> &'static str {
989 match self {
990 Self::Null => "null",
991 Self::Bool(_) => "bool",
992 Self::Int(_) => "int",
993 Self::Float(_) => "float",
994 Self::String(_) => "string",
995 Self::Path { .. } => "path",
996 Self::RangeExpr(_) => "range_expr",
997 Self::Unresolved(_) => "unresolved",
998 _ if self.is_list() => "list",
999 _ => "unknown",
1000 }
1001 }
1002
1003 pub fn to_display_string(&self) -> String {
1005 match self {
1006 Self::Null => "null".to_string(),
1007 Self::Bool(b) => if *b { "true" } else { "false" }.to_string(),
1008 Self::Int(i) => i.to_string(),
1009 Self::Float(fv) => fv.to_display_string(),
1010 Self::String(s) => s.clone(),
1011 Self::Path { value, .. } => value.clone(),
1012 Self::ListBool(v) => format!(
1013 "[{}]",
1014 v.iter()
1015 .map(|b| if *b { "true" } else { "false" })
1016 .collect::<Vec<_>>()
1017 .join(", ")
1018 ),
1019 Self::ListInt(v) => format!(
1020 "[{}]",
1021 v.iter()
1022 .map(|i| i.to_string())
1023 .collect::<Vec<_>>()
1024 .join(", ")
1025 ),
1026 Self::ListFloat(v) => format!(
1027 "[{}]",
1028 v.iter()
1029 .map(|f| f.to_display_string())
1030 .collect::<Vec<_>>()
1031 .join(", ")
1032 ),
1033 Self::ListString(v, _) => format!(
1034 "[{}]",
1035 v.iter()
1036 .map(|s| format!("\"{}\"", s))
1037 .collect::<Vec<_>>()
1038 .join(", ")
1039 ),
1040 Self::ListPath(v, _, _) => format!(
1041 "[{}]",
1042 v.iter()
1043 .map(|s| format!("\"{}\"", s))
1044 .collect::<Vec<_>>()
1045 .join(", ")
1046 ),
1047 Self::ListList(v, _, _) => format!(
1048 "[{}]",
1049 v.iter()
1050 .map(|e| e.to_display_string())
1051 .collect::<Vec<_>>()
1052 .join(", ")
1053 ),
1054 Self::RangeExpr(r) => r.to_string(),
1055 Self::Unresolved(t) => format!("<unresolved[{t}]>"),
1056 }
1057 }
1058
1059 pub fn memory_size(&self) -> usize {
1061 std::mem::size_of::<ExprValue>() + self.heap_size()
1062 }
1063
1064 fn heap_size(&self) -> usize {
1066 use std::mem::size_of;
1067 match self {
1068 Self::Null | Self::Bool(_) | Self::Int(_) | Self::Unresolved(_) => 0,
1069 Self::Float(f) => f.original.as_ref().map_or(0, |s| s.len()),
1070 Self::String(s) | Self::Path { value: s, .. } => s.capacity(),
1071 Self::ListBool(v) => v.capacity(),
1072 Self::ListInt(v) => v.capacity() * size_of::<i64>(),
1073 Self::ListFloat(v) => v.capacity() * size_of::<Float64>(),
1074 Self::ListString(_, cached) | Self::ListPath(_, _, cached) => *cached,
1075 Self::ListList(_, _, cached) => *cached,
1076 Self::RangeExpr(r) => r.heap_size(),
1077 }
1078 }
1079
1080 pub fn equals(&self, other: &ExprValue) -> bool {
1082 match (self, other) {
1083 (Self::Null, Self::Null) => true,
1084 (Self::Bool(a), Self::Bool(b)) => a == b,
1085 (Self::Int(a), Self::Int(b)) => a == b,
1086 (Self::Float(a), Self::Float(b)) => a.value == b.value,
1087 (Self::Int(a), Self::Float(b)) => (*a as f64) == b.value,
1088 (Self::Float(a), Self::Int(b)) => a.value == (*b as f64),
1089 (Self::String(a), Self::String(b)) => a == b,
1090 (Self::Path { value: a, .. }, Self::Path { value: b, .. }) => a == b,
1091 (Self::String(a), Self::Path { value: b, .. })
1092 | (Self::Path { value: b, .. }, Self::String(a)) => a == b,
1093 _ if self.is_list() && other.is_list() => {
1094 let (a_iter, b_iter) = match (self.list_iter(), other.list_iter()) {
1095 (Some(a), Some(b)) => (a, b),
1096 _ => return false,
1097 };
1098 let (a_len, b_len) = (a_iter.len(), b_iter.len());
1099 if a_len != b_len {
1100 return false;
1101 }
1102 a_iter.zip(b_iter).all(|(x, y)| x.equals(&y))
1103 }
1104 (Self::ListInt(elems), Self::RangeExpr(r))
1105 | (Self::RangeExpr(r), Self::ListInt(elems)) => {
1106 let rv: Vec<i64> = r.iter().collect();
1107 elems.len() == rv.len() && elems.iter().zip(rv.iter()).all(|(a, b)| a == b)
1108 }
1109 (Self::RangeExpr(a), Self::RangeExpr(b)) => a == b,
1110 (Self::Unresolved(a), Self::Unresolved(b)) => a == b,
1111 _ => false,
1112 }
1113 }
1114
1115 pub fn compare(
1117 &self,
1118 other: &ExprValue,
1119 ) -> Result<std::cmp::Ordering, crate::error::ExpressionError> {
1120 match (self, other) {
1121 (Self::Int(a), Self::Int(b)) => Ok(a.cmp(b)),
1122 (Self::Float(a), Self::Float(b)) => a
1123 .value
1124 .partial_cmp(&b.value)
1125 .ok_or_else(|| crate::error::ExpressionError::new("Cannot compare NaN")),
1126 (Self::Int(a), Self::Float(b)) => (*a as f64)
1127 .partial_cmp(&b.value)
1128 .ok_or_else(|| crate::error::ExpressionError::new("Cannot compare NaN")),
1129 (Self::Float(a), Self::Int(b)) => a
1130 .value
1131 .partial_cmp(&(*b as f64))
1132 .ok_or_else(|| crate::error::ExpressionError::new("Cannot compare NaN")),
1133 (Self::Bool(a), Self::Bool(b)) => Ok(a.cmp(b)),
1134 (Self::String(a), Self::String(b)) => Ok(a.cmp(b)),
1135 (Self::Path { value: a, .. }, Self::Path { value: b, .. }) => Ok(a.cmp(b)),
1136 (Self::String(a), Self::Path { value: b, .. })
1137 | (Self::Path { value: b, .. }, Self::String(a)) => Ok(a.cmp(b)),
1138 _ if self.is_list() && other.is_list() => {
1139 let (a_iter, b_iter) = match (self.list_iter(), other.list_iter()) {
1140 (Some(a), Some(b)) => (a, b),
1141 _ => {
1142 return Err(crate::error::ExpressionError::new(format!(
1143 "Cannot compare {} and {}",
1144 self.expr_type(),
1145 other.expr_type()
1146 )))
1147 }
1148 };
1149 let (a_len, b_len) = (a_iter.len(), b_iter.len());
1150 for (x, y) in a_iter.zip(b_iter) {
1151 match x.compare(&y) {
1152 Ok(std::cmp::Ordering::Equal) => continue,
1153 other => return other,
1154 }
1155 }
1156 Ok(a_len.cmp(&b_len))
1157 }
1158 _ => Err(crate::error::ExpressionError::new(format!(
1159 "Cannot compare {} and {}",
1160 self.expr_type(),
1161 other.expr_type()
1162 ))),
1163 }
1164 }
1165}
1166
1167impl PartialEq for ExprValue {
1168 fn eq(&self, other: &Self) -> bool {
1169 self.equals(other)
1170 }
1171}
1172
1173impl From<bool> for ExprValue {
1174 fn from(v: bool) -> Self {
1175 Self::Bool(v)
1176 }
1177}
1178impl From<i32> for ExprValue {
1179 fn from(v: i32) -> Self {
1180 Self::Int(v as i64)
1181 }
1182}
1183impl From<i64> for ExprValue {
1184 fn from(v: i64) -> Self {
1185 Self::Int(v)
1186 }
1187}
1188impl From<String> for ExprValue {
1189 fn from(v: String) -> Self {
1190 Self::String(v)
1191 }
1192}
1193impl From<&str> for ExprValue {
1194 fn from(v: &str) -> Self {
1195 Self::String(v.to_string())
1196 }
1197}
1198impl From<RangeExpr> for ExprValue {
1199 fn from(v: RangeExpr) -> Self {
1200 Self::RangeExpr(v)
1201 }
1202}
1203impl From<crate::types::ExprType> for ExprValue {
1204 fn from(t: crate::types::ExprType) -> Self {
1205 Self::Unresolved(t)
1206 }
1207}
1208
1209pub enum ListIter<'a> {
1211 Bool(std::slice::Iter<'a, bool>),
1212 Int(std::slice::Iter<'a, i64>),
1213 Float(std::slice::Iter<'a, Float64>),
1214 String(std::slice::Iter<'a, String>),
1215 Path(std::slice::Iter<'a, String>, PathFormat),
1216 List(std::slice::Iter<'a, ExprValue>),
1217}
1218
1219impl<'a> Iterator for ListIter<'a> {
1220 type Item = ExprValue;
1221 fn next(&mut self) -> Option<ExprValue> {
1222 match self {
1223 Self::Bool(it) => it.next().map(|b| ExprValue::Bool(*b)),
1224 Self::Int(it) => it.next().map(|i| ExprValue::Int(*i)),
1225 Self::Float(it) => it.next().map(|f| ExprValue::Float(f.clone())),
1226 Self::String(it) => it.next().map(|s| ExprValue::String(s.clone())),
1227 Self::Path(it, fmt) => it.next().map(|s| ExprValue::new_path(s.clone(), *fmt)),
1228 Self::List(it) => it.next().cloned(),
1229 }
1230 }
1231 fn size_hint(&self) -> (usize, Option<usize>) {
1232 match self {
1233 Self::Bool(it) => it.size_hint(),
1234 Self::Int(it) => it.size_hint(),
1235 Self::Float(it) => it.size_hint(),
1236 Self::String(it) => it.size_hint(),
1237 Self::Path(it, _) => it.size_hint(),
1238 Self::List(it) => it.size_hint(),
1239 }
1240 }
1241}
1242
1243impl<'a> ExactSizeIterator for ListIter<'a> {}
1244
1245pub fn format_float(f: f64) -> String {
1246 if f == 0.0 {
1247 return "0.0".to_string();
1248 }
1249 let abs = f.abs();
1250 if !(1e-4..1e16).contains(&abs) {
1251 format!("{:e}", f)
1252 .replace("e-0", "e-")
1253 .replace("e0", "e+0")
1254 .replace("e", "e+")
1255 .replace("e+-", "e-")
1256 .replace("e++", "e+")
1257 } else if f.fract() == 0.0 {
1258 format!("{}.0", f as i64)
1259 } else {
1260 f.to_string()
1261 }
1262}
1263
1264#[must_use]
1270pub fn normalize_path_separators(value: &str, format: PathFormat) -> String {
1271 if crate::uri_path::is_uri(value) {
1272 return value.to_string();
1273 }
1274 match format {
1275 PathFormat::Windows => value.replace('/', "\\"),
1276 PathFormat::Posix | PathFormat::Uri => value.to_string(),
1277 }
1278}