1use crate::error::{Error, Result};
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12use std::collections::HashMap;
13use std::fmt;
14use std::str::FromStr;
15
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub enum Value<T> {
34 Literal(T),
36 Parameter(String),
38 Expression(String),
40}
41
42impl<T> Value<T>
43where
44 T: FromStr + Clone,
45 T::Err: std::fmt::Display,
46{
47 pub fn resolve(&self, params: &HashMap<String, String>) -> Result<T> {
49 match self {
50 Value::Literal(value) => Ok(value.clone()),
51 Value::Parameter(param_name) => {
52 let param_value = params
53 .get(param_name)
54 .ok_or_else(|| Error::parameter_error(param_name, "parameter not found"))?;
55
56 param_value.parse::<T>().map_err(|e| {
57 Error::parameter_error(
58 param_name,
59 &format!("failed to parse '{}': {}", param_value, e),
60 )
61 })
62 }
63 Value::Expression(expr) => {
64 let resolved_expr = resolve_expression::<T>(expr, params)?;
67 resolved_expr.parse::<T>().map_err(|e| {
68 Error::parameter_error(
69 expr,
70 &format!(
71 "failed to parse expression result '{}': {}",
72 resolved_expr, e
73 ),
74 )
75 })
76 }
77 }
78 }
79
80 #[inline]
82 pub fn as_literal(&self) -> Option<&T> {
83 match self {
84 Value::Literal(value) => Some(value),
85 Value::Parameter(_) => None,
86 Value::Expression(_) => None,
87 }
88 }
89
90 #[inline]
92 pub fn as_parameter(&self) -> Option<&str> {
93 match self {
94 Value::Literal(_) => None,
95 Value::Parameter(name) => Some(name),
96 Value::Expression(_) => None,
97 }
98 }
99
100 #[inline]
102 pub fn as_expression(&self) -> Option<&str> {
103 match self {
104 Value::Literal(_) => None,
105 Value::Parameter(_) => None,
106 Value::Expression(expr) => Some(expr),
107 }
108 }
109}
110
111impl<T: Clone> Value<T> {
112 #[inline]
114 pub fn literal(value: T) -> Self {
115 Value::Literal(value)
116 }
117
118 #[inline]
120 pub fn parameter(name: String) -> Self {
121 Value::Parameter(name)
122 }
123
124 #[inline]
126 pub fn expression(expr: String) -> Self {
127 Value::Expression(expr)
128 }
129}
130
131impl<'de, T> Deserialize<'de> for Value<T>
133where
134 T: Deserialize<'de> + FromStr,
135 T::Err: std::fmt::Display,
136{
137 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
138 where
139 D: Deserializer<'de>,
140 {
141 let s = String::deserialize(deserializer)?;
142
143 if s.is_empty() && std::any::type_name::<T>().contains("f64") {
145 return Err(serde::de::Error::custom(
146 "Empty string is not a valid value for Double type",
147 ));
148 }
149
150 if s.starts_with("${") && s.ends_with('}') && s.len() > 3 {
152 let content = &s[2..s.len() - 1];
153 if is_valid_parameter_name(content) && !content.contains(|c| "+-*/%()".contains(c)) {
155 Ok(Value::Parameter(content.to_string()))
156 } else {
157 Ok(Value::Expression(content.to_string()))
159 }
160 } else if s.starts_with("$") && s.len() > 1 {
161 let content = &s[1..];
163 if is_valid_parameter_name(content) && !content.contains(|c| "+-*/%()".contains(c)) {
164 Ok(Value::Parameter(content.to_string()))
165 } else {
166 match s.parse::<T>() {
168 Ok(value) => Ok(Value::Literal(value)),
169 Err(e) => Err(serde::de::Error::custom(format!(
170 "Failed to parse '{}': {}",
171 s, e
172 ))),
173 }
174 }
175 } else {
176 match s.parse::<T>() {
178 Ok(value) => Ok(Value::Literal(value)),
179 Err(e) => Err(serde::de::Error::custom(format!(
180 "Failed to parse '{}': {}",
181 s, e
182 ))),
183 }
184 }
185 }
186}
187
188impl<T> Serialize for Value<T>
189where
190 T: Serialize + fmt::Display,
191{
192 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
193 where
194 S: Serializer,
195 {
196 match self {
197 Value::Literal(value) => value.to_string().serialize(serializer),
198 Value::Parameter(name) => format!("${{{}}}", name).serialize(serializer),
199 Value::Expression(expr) => format!("${{{}}}", expr).serialize(serializer),
200 }
201 }
202}
203
204impl<T> fmt::Display for Value<T>
206where
207 T: fmt::Display,
208{
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 match self {
211 Value::Literal(value) => write!(f, "{}", value),
212 Value::Parameter(name) => write!(f, "${{{}}}", name),
213 Value::Expression(expr) => write!(f, "${{{}}}", expr),
214 }
215 }
216}
217
218pub type OSString = Value<String>;
220pub type Double = Value<f64>;
221pub type Int = Value<i32>;
222pub type UnsignedInt = Value<u32>;
223pub type UnsignedShort = Value<u16>;
224pub type Boolean = Value<bool>;
225
226pub type DateTime = Value<chrono::DateTime<chrono::Utc>>;
227
228
229
230pub fn parse_parameter_reference(s: &str) -> Option<String> {
234 if s.starts_with("${") && s.ends_with('}') && s.len() > 3 {
235 let param_name = &s[2..s.len() - 1];
236 if is_valid_parameter_name(param_name) {
237 Some(param_name.to_string())
238 } else {
239 None
240 }
241 } else {
242 None
243 }
244}
245
246#[inline]
248pub fn is_expression(s: &str) -> bool {
249 s.contains(|c| "+-*/%()".contains(c))
250}
251
252pub fn is_valid_parameter_name(name: &str) -> bool {
256 !name.is_empty()
257 && name.chars().all(|c| c.is_alphanumeric() || c == '_')
258 && !name.chars().next().unwrap().is_ascii_digit() }
260
261fn resolve_expression<T: FromStr>(expr: &str, params: &HashMap<String, String>) -> Result<String>
265where
266 T::Err: std::fmt::Display,
267{
268 match crate::expression::evaluate_expression::<f64>(expr, params) {
270 Ok(result) => Ok(result.to_string()),
271 Err(_) => {
272 let mut result = expr.to_string();
274
275 for (param_name, param_value) in params {
277 let param_ref = format!("${{{}}}", param_name);
278 if result.contains(¶m_ref) {
279 result = result.replace(¶m_ref, param_value);
280 }
281 }
282
283 Ok(result)
284 }
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291 use quick_xml;
292
293 #[test]
294 fn test_parameter_reference_parsing() {
295 assert_eq!(
296 parse_parameter_reference("${speed}"),
297 Some("speed".to_string())
298 );
299 assert_eq!(
300 parse_parameter_reference("${vehicle_speed}"),
301 Some("vehicle_speed".to_string())
302 );
303 assert_eq!(parse_parameter_reference("literal"), None);
304 assert_eq!(parse_parameter_reference("${}"), None);
305 assert_eq!(parse_parameter_reference("${123}"), None); }
307
308 #[test]
309 fn test_parameter_name_validation() {
310 assert!(is_valid_parameter_name("speed"));
311 assert!(is_valid_parameter_name("vehicle_speed"));
312 assert!(is_valid_parameter_name("speed123"));
313 assert!(!is_valid_parameter_name("123speed")); assert!(!is_valid_parameter_name("")); assert!(!is_valid_parameter_name("speed-limit")); }
317
318 #[test]
319 fn test_value_creation() {
320 let literal = Value::<f64>::literal(10.0);
321 assert!(matches!(literal, Value::Literal(10.0)));
322
323 let parameter = Value::<String>::parameter("speed".to_string());
324 assert!(matches!(parameter, Value::Parameter(_)));
325
326 let expression = Value::<String>::expression("speed + 10".to_string());
327 assert!(matches!(expression, Value::Expression(_)));
328 }
329
330 #[test]
331 fn test_value_resolution() {
332 let mut params = HashMap::new();
333 params.insert("speed".to_string(), "30.0".to_string());
334 params.insert("acceleration".to_string(), "2.5".to_string());
335
336 let literal = Value::<f64>::literal(10.0);
338 assert_eq!(literal.resolve(¶ms).unwrap(), 10.0);
339
340 let parameter = Value::<f64>::parameter("speed".to_string());
342 assert_eq!(parameter.resolve(¶ms).unwrap(), 30.0);
343
344 let expression = Value::<String>::expression("speed".to_string());
346 assert_eq!(expression.resolve(¶ms).unwrap(), "30");
347 }
348
349 #[test]
350 fn test_parameter_declaration_creation() {
351 let param = ParameterDeclaration::new(
353 "MaxSpeed".to_string(),
354 ParameterType::Double,
355 "60.0".to_string(),
356 );
357
358 assert_eq!(param.name.as_literal().unwrap(), "MaxSpeed");
359 assert_eq!(param.parameter_type, ParameterType::Double);
360 assert_eq!(param.value.as_literal().unwrap(), "60.0");
361 assert!(!param.has_constraints());
362 }
363
364 #[test]
365 fn test_parameter_declaration_with_constraints() {
366 let constraints = ValueConstraintGroup::new(vec![
367 ValueConstraint::greater_than("0.0".to_string()),
368 ValueConstraint::less_than("100.0".to_string()),
369 ]);
370
371 let param = ParameterDeclaration::with_constraints(
372 "Speed".to_string(),
373 ParameterType::Double,
374 "30.0".to_string(),
375 vec![constraints],
376 );
377
378 assert!(param.has_constraints());
379 let constraint_group = ¶m.constraint_groups[0];
380 assert_eq!(constraint_group.value_constraints.len(), 2);
381 assert_eq!(
382 constraint_group.value_constraints[0].rule,
383 Rule::GreaterThan
384 );
385 assert_eq!(constraint_group.value_constraints[1].rule, Rule::LessThan);
386 }
387
388 #[test]
389 fn test_parameter_declaration_add_constraint() {
390 let mut param =
391 ParameterDeclaration::new("Age".to_string(), ParameterType::Int, "25".to_string());
392
393 assert!(!param.has_constraints());
395
396 param.add_constraint(ValueConstraint::greater_than("0".to_string()));
398 assert!(param.has_constraints());
399
400 param.add_constraint(ValueConstraint::less_than("120".to_string()));
402
403 let constraints = ¶m.constraint_groups[0];
404 assert_eq!(constraints.value_constraints.len(), 2);
405 }
406
407 #[test]
408 fn test_value_constraint_helpers() {
409 let eq_constraint = ValueConstraint::equal_to("test".to_string());
410 assert_eq!(eq_constraint.rule, Rule::EqualTo);
411 assert_eq!(eq_constraint.value.as_literal().unwrap(), "test");
412
413 let gt_constraint = ValueConstraint::greater_than("10".to_string());
414 assert_eq!(gt_constraint.rule, Rule::GreaterThan);
415
416 let lt_constraint = ValueConstraint::less_than("50".to_string());
417 assert_eq!(lt_constraint.rule, Rule::LessThan);
418 }
419
420 #[test]
421 fn test_range_creation() {
422 let range = Range::new(0.0, 100.0);
423 assert_eq!(range.lower_limit.as_literal().unwrap(), &0.0);
424 assert_eq!(range.upper_limit.as_literal().unwrap(), &100.0);
425
426 let default_range = Range::default();
427 assert_eq!(default_range.lower_limit.as_literal().unwrap(), &0.0);
428 assert_eq!(default_range.upper_limit.as_literal().unwrap(), &100.0);
429 }
430
431 #[test]
432 fn test_parameter_declarations_container() {
433 let mut declarations = ParameterDeclarations::default();
434 assert!(declarations.parameter_declarations.is_empty());
435
436 declarations
437 .parameter_declarations
438 .push(ParameterDeclaration::new(
439 "Speed".to_string(),
440 ParameterType::Double,
441 "30.0".to_string(),
442 ));
443
444 declarations
445 .parameter_declarations
446 .push(ParameterDeclaration::new(
447 "VehicleName".to_string(),
448 ParameterType::String,
449 "Ego".to_string(),
450 ));
451
452 assert_eq!(declarations.parameter_declarations.len(), 2);
453 assert_eq!(
454 declarations.parameter_declarations[0].parameter_type,
455 ParameterType::Double
456 );
457 assert_eq!(
458 declarations.parameter_declarations[1].parameter_type,
459 ParameterType::String
460 );
461 }
462
463 #[test]
464 fn test_directory_creation() {
465 let dir = Directory::new("/path/to/catalogs".to_string());
467 assert_eq!(dir.path.as_literal().unwrap(), "/path/to/catalogs");
468
469 let param_dir = Directory::from_parameter("CatalogPath".to_string());
471 assert_eq!(param_dir.path.as_parameter().unwrap(), "CatalogPath");
472
473 let default_dir = Directory::default();
475 assert_eq!(default_dir.path.as_literal().unwrap(), "");
476 }
477
478 #[test]
479 fn test_directory_path_resolution() {
480 let mut params = HashMap::new();
481 params.insert("CatalogPath".to_string(), "/catalogs/vehicles".to_string());
482
483 let dir = Directory::new("/path/to/catalogs".to_string());
485 assert_eq!(dir.resolve_path(¶ms).unwrap(), "/path/to/catalogs");
486
487 let param_dir = Directory::from_parameter("CatalogPath".to_string());
489 assert_eq!(
490 param_dir.resolve_path(¶ms).unwrap(),
491 "/catalogs/vehicles"
492 );
493 }
494
495 #[test]
496 fn test_directory_path_validation() {
497 let valid_dir = Directory::new("/path/to/catalogs".to_string());
499 assert!(valid_dir.validate_path());
500
501 let relative_dir = Directory::new("./catalogs".to_string());
502 assert!(relative_dir.validate_path());
503
504 let empty_dir = Directory::new("".to_string());
506 assert!(!empty_dir.validate_path());
507
508 let null_dir = Directory::new("path\0with\0null".to_string());
509 assert!(!null_dir.validate_path());
510
511 let param_dir = Directory::from_parameter("CatalogPath".to_string());
513 assert!(param_dir.validate_path());
514 }
515
516 #[test]
517 fn test_directory_serialization() {
518 let dir = Directory::new("/path/to/catalogs".to_string());
519
520 let json = serde_json::to_string(&dir).unwrap();
522 assert!(json.contains("path"));
523 assert!(json.contains("/path/to/catalogs"));
524
525 let deserialized: Directory = serde_json::from_str(&json).unwrap();
527 assert_eq!(deserialized.path.as_literal().unwrap(), "/path/to/catalogs");
528 }
529
530 #[test]
531 fn test_scientific_notation_parsing() {
532 let test_values = [
534 "0.0000000000000000e+00",
535 "1.5000000000000000e+00",
536 "9.2884257876425379e-04",
537 "3.7479999999999983e+01",
538 "-2.8099999999999987e+00",
539 ];
540
541 for val in test_values {
542 println!("Testing: '{}'", val);
543
544 match val.parse::<f64>() {
546 Ok(f) => println!(" Direct f64::parse: {}", f),
547 Err(e) => println!(" Direct f64::parse ERROR: {}", e),
548 }
549
550 let json_str = format!("\"{}\"", val);
552 match serde_json::from_str::<Double>(&json_str) {
553 Ok(double_val) => {
554 println!(" Value<f64> JSON: {:?}", double_val);
555 if let Some(literal_val) = double_val.as_literal() {
556 println!(" Literal value: {}", literal_val);
557 }
558 }
559 Err(e) => println!(" Value<f64> JSON ERROR: {}", e),
560 }
561
562 let xml_str = format!("<test>{}</test>", val);
564 match quick_xml::de::from_str::<Double>(&xml_str) {
565 Ok(double_val) => {
566 println!(" Value<f64> XML: {:?}", double_val);
567 if let Some(literal_val) = double_val.as_literal() {
568 println!(" XML Literal value: {}", literal_val);
569 }
570 }
571 Err(e) => println!(" Value<f64> XML ERROR: {}", e),
572 }
573 println!();
574 }
575 }
576
577 #[test]
578 fn test_parameter_declaration_multiple_constraint_groups() {
579 let constraint_group1 =
581 ValueConstraintGroup::new(vec![ValueConstraint::equal_to("1".to_string())]);
582
583 let constraint_group2 =
584 ValueConstraintGroup::new(vec![ValueConstraint::equal_to("-1".to_string())]);
585
586 let param = ParameterDeclaration::with_constraints(
587 "SideVehicle_InitPosition_RelativeLaneId".to_string(),
588 ParameterType::Int,
589 "1".to_string(),
590 vec![constraint_group1, constraint_group2],
591 );
592
593 assert!(param.has_constraints());
595 assert_eq!(param.constraint_groups.len(), 2);
596
597 assert_eq!(param.constraint_groups[0].value_constraints.len(), 1);
599 assert_eq!(
600 param.constraint_groups[0].value_constraints[0].rule,
601 Rule::EqualTo
602 );
603 assert_eq!(
604 param.constraint_groups[0].value_constraints[0]
605 .value
606 .as_literal()
607 .unwrap(),
608 "1"
609 );
610
611 assert_eq!(param.constraint_groups[1].value_constraints.len(), 1);
613 assert_eq!(
614 param.constraint_groups[1].value_constraints[0].rule,
615 Rule::EqualTo
616 );
617 assert_eq!(
618 param.constraint_groups[1].value_constraints[0]
619 .value
620 .as_literal()
621 .unwrap(),
622 "-1"
623 );
624 }
625
626 #[test]
627 fn test_alks_scenario_constraint_pattern() {
628 let xml = r#"
630 <ParameterDeclaration name="SideVehicle_InitPosition_RelativeLaneId" parameterType="int" value="1">
631 <ConstraintGroup>
632 <ValueConstraint rule="equalTo" value="1"></ValueConstraint>
633 </ConstraintGroup>
634 <ConstraintGroup>
635 <ValueConstraint rule="equalTo" value="-1"></ValueConstraint>
636 </ConstraintGroup>
637 </ParameterDeclaration>
638 "#;
639
640 let result = quick_xml::de::from_str::<ParameterDeclaration>(xml);
642 assert!(
643 result.is_ok(),
644 "Failed to parse ALKS constraint pattern: {:?}",
645 result.err()
646 );
647
648 let param = result.unwrap();
649 assert_eq!(
650 param.name.as_literal().unwrap(),
651 "SideVehicle_InitPosition_RelativeLaneId"
652 );
653 assert_eq!(param.parameter_type, ParameterType::Int);
654 assert_eq!(param.value.as_literal().unwrap(), "1");
655 assert_eq!(param.constraint_groups.len(), 2);
656 }
657
658 #[test]
659 fn test_value_display_trait() {
660 let literal_value = Value::<f64>::literal(42.5);
662 assert_eq!(format!("{}", literal_value), "42.5");
663
664 let parameter_value = Value::<String>::parameter("speed".to_string());
665 assert_eq!(format!("{}", parameter_value), "${speed}");
666
667 let expression_value = Value::<String>::expression("speed * 2".to_string());
668 assert_eq!(format!("{}", expression_value), "${speed * 2}");
669
670 let bool_literal = Value::<bool>::literal(true);
672 assert_eq!(format!("{}", bool_literal), "true");
673
674 let string_literal = Value::<String>::literal("hello".to_string());
675 assert_eq!(format!("{}", string_literal), "hello");
676
677 let double_value = Double::literal(3.14);
679 assert_eq!(format!("{}", double_value), "3.14");
680
681 let os_string_param = OSString::parameter("vehicle_name".to_string());
682 assert_eq!(format!("{}", os_string_param), "${vehicle_name}");
683
684 let boolean_expr = Boolean::expression("speed > 30".to_string());
685 assert_eq!(format!("{}", boolean_expr), "${speed > 30}");
686 }
687}
688
689use crate::types::enums::{ParameterType, Rule};
692
693#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
695pub struct ParameterDeclarations {
696 #[serde(rename = "ParameterDeclaration", default)]
697 pub parameter_declarations: Vec<ParameterDeclaration>,
698}
699
700#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
702pub struct ParameterDeclaration {
703 #[serde(rename = "@name")]
704 pub name: OSString,
705 #[serde(rename = "@parameterType")]
706 pub parameter_type: ParameterType,
707 #[serde(rename = "@value")]
708 pub value: OSString,
709 #[serde(
710 rename = "ConstraintGroup",
711 default,
712 skip_serializing_if = "Vec::is_empty"
713 )]
714 pub constraint_groups: Vec<ValueConstraintGroup>,
715}
716
717impl Default for ParameterDeclaration {
718 fn default() -> Self {
719 Self {
720 name: OSString::literal("DefaultParameter".to_string()),
721 parameter_type: ParameterType::String,
722 value: OSString::literal("".to_string()),
723 constraint_groups: Vec::new(),
724 }
725 }
726}
727
728#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
730pub struct ValueConstraintGroup {
731 #[serde(rename = "ValueConstraint")]
732 pub value_constraints: Vec<ValueConstraint>,
733}
734
735#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
737pub struct ValueConstraint {
738 #[serde(rename = "@rule")]
739 pub rule: Rule,
740 #[serde(rename = "@value")]
741 pub value: OSString,
742}
743
744#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
746pub struct Range {
747 #[serde(rename = "@lowerLimit")]
748 pub lower_limit: Double,
749 #[serde(rename = "@upperLimit")]
750 pub upper_limit: Double,
751}
752
753impl Default for ValueConstraint {
754 fn default() -> Self {
755 Self {
756 rule: Rule::EqualTo,
757 value: OSString::literal("0".to_string()),
758 }
759 }
760}
761
762impl Default for Range {
763 fn default() -> Self {
764 Self {
765 lower_limit: Double::literal(0.0),
766 upper_limit: Double::literal(100.0),
767 }
768 }
769}
770
771impl ParameterDeclaration {
773 pub fn new(name: String, parameter_type: ParameterType, value: String) -> Self {
775 Self {
776 name: OSString::literal(name),
777 parameter_type,
778 value: OSString::literal(value),
779 constraint_groups: Vec::new(),
780 }
781 }
782
783 pub fn with_constraints(
785 name: String,
786 parameter_type: ParameterType,
787 value: String,
788 constraints: Vec<ValueConstraintGroup>,
789 ) -> Self {
790 Self {
791 name: OSString::literal(name),
792 parameter_type,
793 value: OSString::literal(value),
794 constraint_groups: constraints,
795 }
796 }
797
798 pub fn add_constraint(&mut self, constraint: ValueConstraint) {
800 if let Some(group) = self.constraint_groups.last_mut() {
801 group.value_constraints.push(constraint);
802 } else {
803 self.constraint_groups.push(ValueConstraintGroup {
804 value_constraints: vec![constraint],
805 });
806 }
807 }
808
809 pub fn has_constraints(&self) -> bool {
811 !self.constraint_groups.is_empty()
812 }
813}
814
815#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
821pub struct Directory {
822 #[serde(rename = "@path")]
824 pub path: OSString,
825}
826
827impl Directory {
829 pub fn new(path: String) -> Self {
831 Self {
832 path: OSString::literal(path),
833 }
834 }
835
836 pub fn from_parameter(param_name: String) -> Self {
838 Self {
839 path: OSString::parameter(param_name),
840 }
841 }
842
843 pub fn resolve_path(&self, params: &HashMap<String, String>) -> Result<String> {
845 self.path.resolve(params)
846 }
847
848 pub fn validate_path(&self) -> bool {
850 if let Some(literal_path) = self.path.as_literal() {
851 !literal_path.is_empty() && !literal_path.contains('\0')
852 } else {
853 true
855 }
856 }
857}
858
859impl Default for Directory {
860 fn default() -> Self {
861 Self::new(String::new())
862 }
863}
864
865impl ValueConstraintGroup {
867 pub fn new(constraints: Vec<ValueConstraint>) -> Self {
869 Self {
870 value_constraints: constraints,
871 }
872 }
873
874 pub fn add_constraint(&mut self, constraint: ValueConstraint) {
876 self.value_constraints.push(constraint);
877 }
878}
879
880impl ValueConstraint {
882 pub fn new(rule: Rule, value: String) -> Self {
884 Self {
885 rule,
886 value: OSString::literal(value),
887 }
888 }
889
890 pub fn equal_to(value: String) -> Self {
892 Self::new(Rule::EqualTo, value)
893 }
894
895 pub fn greater_than(value: String) -> Self {
897 Self::new(Rule::GreaterThan, value)
898 }
899
900 pub fn less_than(value: String) -> Self {
902 Self::new(Rule::LessThan, value)
903 }
904}
905
906impl Range {
908 pub fn new(lower: f64, upper: f64) -> Self {
913 debug_assert!(lower <= upper, "Range lower limit must be <= upper limit");
914 Self {
915 lower_limit: Double::literal(lower),
916 upper_limit: Double::literal(upper),
917 }
918 }
919
920 pub fn try_new(lower: f64, upper: f64) -> Result<Self> {
922 if lower > upper {
923 return Err(Error::validation_error(
924 "Range",
925 "Range lower limit must be <= upper limit",
926 ));
927 }
928 Ok(Self {
929 lower_limit: Double::literal(lower),
930 upper_limit: Double::literal(upper),
931 })
932 }
933}