dsntk_feel/
values.rs

1//! # FEEL values
2
3use crate::bif::Bif;
4use crate::closure::Closure;
5use crate::context::FeelContext;
6use crate::errors::*;
7use crate::names::Name;
8use crate::strings::ToFeelString;
9use crate::types::FeelType;
10use crate::FunctionBody;
11use dsntk_common::{Jsonify, Result};
12use dsntk_feel_number::FeelNumber;
13use dsntk_feel_temporal::{FeelDate, FeelDateTime, FeelDaysAndTimeDuration, FeelTime, FeelYearsAndMonthsDuration};
14use std::borrow::Borrow;
15use std::collections::BTreeMap;
16use std::fmt;
17use std::fmt::Display;
18use std::ops::Deref;
19use std::str::FromStr;
20
21/// Creates `Value::Null` with optional tracing message.
22///
23/// # Examples
24///
25/// ```
26/// use crate::dsntk_feel::{value_null, values::Value};
27///
28/// let v = value_null!();
29/// assert_eq!("null", v.to_string());
30///
31/// let v = value_null!("missing input parameter");
32/// assert_eq!("null(missing input parameter)", v.to_string());
33///
34/// let v = value_null!("integer out of range {}..{}", 1, 100);
35/// assert_eq!("null(integer out of range 1..100)", v.to_string());
36/// ```
37#[macro_export]
38macro_rules! value_null {
39  ($module:expr, $function:literal, $format:literal, $($arguments:tt)*) => {
40    Value::Null(Some(format!("[{}::{}] {}", $module, $function, format!($format, $($arguments)*))))
41  };
42  ($format:literal, $($arguments:tt)*) => {
43    Value::Null(Some(format!($format, $($arguments)*)))
44  };
45  ($argument:expr) => {
46    Value::Null(Some(format!("{}", $argument)))
47  };
48  () => {
49    Value::Null(None)
50  };
51}
52
53#[macro_export]
54macro_rules! value_number {
55  ($n:expr) => {{
56    Value::Number($n.into())
57  }};
58  ($n:expr, $s:expr) => {
59    Value::Number(FeelNumber::new($n, $s))
60  };
61}
62
63#[macro_export]
64macro_rules! value_string {
65  ($s:literal) => {{
66    Value::String($s.to_string())
67  }};
68  ($s:expr) => {{
69    Value::String($s)
70  }};
71}
72
73/// Utility constant for value `true `of type `Boolean`.
74pub const VALUE_TRUE: Value = Value::Boolean(true);
75
76/// Utility constant for value `false` of type `Boolean`.
77pub const VALUE_FALSE: Value = Value::Boolean(false);
78
79/// Constant indicating invalid coercion result.
80const INVALID_COERCION: &str = "after coercion";
81
82/// `FEEL` value.
83#[derive(Debug, Clone, PartialEq)]
84pub enum Value {
85  /// Value representing `FEEL` boolean type.
86  Boolean(bool),
87
88  /// Value for storing built-in function definition.
89  BuiltInFunction(Bif),
90
91  /// Value representing a context.
92  Context(FeelContext),
93
94  /// Value representing a context entry.
95  ContextEntry(Name, Box<Value>),
96
97  /// Value representing a key of the context entry.
98  ContextEntryKey(Name),
99
100  /// Value representing the context type.
101  ContextType(FeelType),
102
103  /// Value representing a context entry in context type definition.
104  ContextTypeEntry(Name, FeelType),
105
106  /// Value representing a key of the context entry in context type definition.
107  ContextTypeEntryKey(Name),
108
109  /// Value for storing dates as [FeelDate].
110  Date(FeelDate),
111
112  /// Value for storing date and time as [FeelDateTime].
113  DateTime(FeelDateTime),
114
115  /// Value for days and time durations.
116  DaysAndTimeDuration(FeelDaysAndTimeDuration),
117
118  /// Value representing a collection of comma-separated list of expressions.
119  ExpressionList(Values),
120
121  /// Value representing a mapping to externally defined `Java` function.
122  ExternalJavaFunction(
123    /// Class name.
124    String,
125    /// Method signature.
126    String,
127  ),
128
129  /// Value representing a mapping to externally defined `PMML` function.
130  ExternalPmmlFunction(
131    /// Document.
132    String,
133    /// Model name.
134    String,
135  ),
136
137  /// Value representing the `FEEL` type of a value.
138  FeelType(FeelType),
139
140  /// Value representing function's formal parameter with name and type.
141  FormalParameter(Name, FeelType),
142
143  /// List of formal parameters.
144  FormalParameters(Vec<(Name, FeelType)>),
145
146  /// Definition of the function body.
147  FunctionBody(
148    /// Body of the function.
149    FunctionBody,
150    /// Flag indicating if the function's body is an external function, `true` == external.
151    bool,
152  ),
153
154  /// Value representing the function definition.
155  /// This value holds the list of function's formal parameters, the function's body, closure for lambdas and expected result type.
156  FunctionDefinition(
157    /// Formal parameters of the function.
158    Vec<(Name, FeelType)>,
159    /// Body of the function.
160    FunctionBody,
161    /// Flag indicating if the function's body is an external function, `true` == external.
162    bool,
163    /// Closed names from function context (closure names).
164    Closure,
165    /// Values of the closed names (closure values).
166    FeelContext,
167    /// Return type of the function.
168    FeelType,
169  ),
170
171  /// Value representing interval end.
172  IntervalEnd(Box<Value>, bool),
173
174  /// Value representing interval start.
175  IntervalStart(Box<Value>, bool),
176
177  /// Value representing `FEEL` `irrelevant` value.
178  Irrelevant,
179
180  /// Value representing a list of values.
181  List(Values),
182
183  /// Named parameter.
184  NamedParameter(Box<Value>, Box<Value>),
185
186  /// Value representing a collection of named parameters.
187  NamedParameters(BTreeMap<Name, (Value, usize)>),
188
189  /// Value representing a collection of values representing a negated comma-separated list of expressions.
190  NegatedCommaList(Values),
191
192  /// Null value with optional tracing message.
193  Null(Option<String>),
194
195  /// Value representing `FEEL` number type.
196  Number(FeelNumber),
197
198  /// Name of the parameter.
199  ParameterName(Name),
200
201  /// Value representing a list of function's parameter types.
202  ParameterTypes(Vec<Value>),
203
204  /// List of positional parameters.
205  PositionalParameters(Values),
206
207  /// Value representing a segment of a qualified name.
208  QualifiedNameSegment(Name),
209
210  /// Value representing a `range`.
211  Range(Box<Value>, bool, Box<Value>, bool),
212
213  /// `String` value...
214  String(String),
215
216  /// Value for storing time as [FeelTime].
217  Time(FeelTime),
218
219  /// Value representing unary `>`.
220  UnaryGreater(
221    /// Value on the right side of the unary `>` operator.
222    Box<Value>,
223  ),
224
225  /// Value representing unary `>=`.
226  UnaryGreaterOrEqual(
227    /// Value on the right side of the unary `>=` operator.
228    Box<Value>,
229  ),
230
231  /// Value representing unary `<`.
232  UnaryLess(
233    /// Value on the right side of the unary `<` operator.
234    Box<Value>,
235  ),
236
237  /// Value representing unary `<=`.
238  UnaryLessOrEqual(
239    /// Value on the right side of the unary `<=` operator.
240    Box<Value>,
241  ),
242
243  /// Value representing unary `=`.
244  UnaryEqual(
245    /// Value on the right side of the unary `=` operator.
246    Box<Value>,
247  ),
248
249  /// Value representing unary `!=`.
250  UnaryNotEqual(
251    /// Value on the right side of the unary `!=` operator.
252    Box<Value>,
253  ),
254
255  /// Value that is "bubbled-up" without any processing.
256  Transparent(Box<Value>),
257
258  /// Value for storing years and months duration.
259  YearsAndMonthsDuration(FeelYearsAndMonthsDuration),
260}
261
262impl Display for Value {
263  /// Implements [Display] for a [Value].
264  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265    match self {
266      Value::Boolean(value) => write!(f, "{value}"),
267      Value::BuiltInFunction(_) => write!(f, "BuiltInFunction"),
268      Value::Context(context) => write!(f, "{context}"),
269      Value::ContextEntry(_, _) => write!(f, "ContextEntry"),
270      Value::ContextEntryKey(name) => write!(f, "{name}"),
271      Value::ContextType(_) => write!(f, "ContextType"),
272      Value::ContextTypeEntry(name, feel_type) => write!(f, "{name}: {feel_type}"),
273      Value::ContextTypeEntryKey(name) => write!(f, "{name}"),
274      Value::Date(date) => write!(f, "{date}"),
275      Value::DateTime(date_time) => write!(f, "{date_time}"),
276      Value::DaysAndTimeDuration(dt_duration) => write!(f, "{dt_duration}"),
277      Value::ExpressionList(items) => write!(f, "{}", values_to_string(items)),
278      Value::ExternalJavaFunction(class_name, method_signature) => write!(f, "ExternalJavaFunction({class_name}, {method_signature})"),
279      Value::ExternalPmmlFunction(iri, model_name) => write!(f, "ExternalPmmlFunction({iri}, {model_name})"),
280      Value::FeelType(feel_type) => write!(f, "type({feel_type})"),
281      Value::FormalParameter(_, _) => write!(f, "FormalParameter"),
282      Value::FormalParameters(_) => write!(f, "FormalParameters"),
283      Value::FunctionBody(_, external) => write!(f, "FunctionBody{}", if *external { " (external)" } else { "" }),
284      Value::FunctionDefinition(parameters, _body, external, closure, closure_ctx, return_type) => {
285        write!(f, "FunctionDefinition({parameters:?},_,{external},{closure},{closure_ctx},{return_type})")
286      }
287      Value::IntervalEnd(_, _) => write!(f, "IntervalEnd"),
288      Value::IntervalStart(_, _) => write!(f, "IntervalStart"),
289      Value::Irrelevant => write!(f, "Irrelevant"),
290      Value::List(items) => write!(f, "{}", values_to_string(items)),
291      Value::NamedParameter(_, _) => write!(f, "NamedParameter"),
292      Value::NamedParameters(_) => write!(f, "NamedParameters"),
293      Value::NegatedCommaList(_) => write!(f, "NegatedCommaList"),
294      Value::Number(value) => write!(f, "{value}"),
295      Value::Null(trace) => write!(f, "null{}", trace.as_ref().map_or("".to_string(), |s| format!("({s})"))),
296      Value::ParameterName(_) => write!(f, "ParameterName"),
297      Value::ParameterTypes(_) => write!(f, "ParameterTypes"),
298      Value::PositionalParameters(_) => write!(f, "PositionalParameters"),
299      Value::QualifiedNameSegment(_) => write!(f, "QualifiedNameSegment"),
300      Value::Range(v1, c1, v2, c2) => write!(
301        f,
302        "{}{}..{}{}",
303        if *c1 { '[' } else { '(' },
304        if v1.is_null() { "".to_string() } else { v1.to_string() },
305        if v2.is_null() { "".to_string() } else { v2.to_string() },
306        if *c2 { ']' } else { ')' }
307      ),
308      Value::String(s) => write!(f, "\"{s}\""),
309      Value::Time(time) => write!(f, "{time}"),
310      Value::UnaryGreater(value) => write!(f, "UnaryGreater({value})"),
311      Value::UnaryGreaterOrEqual(value) => write!(f, "UnaryGreaterOrEqual({value})"),
312      Value::UnaryLess(value) => write!(f, "UnaryLess({value})"),
313      Value::UnaryLessOrEqual(value) => write!(f, "UnaryLessOrEqual({value})"),
314      Value::UnaryEqual(value) => write!(f, "UnaryEqual({value})"),
315      Value::UnaryNotEqual(value) => write!(f, "UnaryNotEqual({value})"),
316      Value::Transparent(value) => write!(f, "Transparent({value})"),
317      Value::YearsAndMonthsDuration(ym_duration) => write!(f, "{ym_duration}"),
318    }
319  }
320}
321
322impl ToFeelString for Value {
323  /// Converts [Value] into `FEEL` string.
324  fn to_feel_string(&self) -> String {
325    match self {
326      Value::Context(context) => context.to_feel_string(),
327      Value::List(items) => values_to_feel_string(items),
328      Value::String(value) => format!("\"{}\"", value.replace('"', "\\\"")),
329      other => other.to_string(),
330    }
331  }
332}
333
334impl Jsonify for Value {
335  /// Converts a [Value] into `JSON`.
336  fn jsonify(&self) -> String {
337    match self {
338      Value::Boolean(value) => format!("{value}"),
339      Value::Number(value) => value.jsonify(),
340      Value::String(s) => format!(r#""{s}""#),
341      Value::Date(date) => format!(r#""{}""#, date),
342      Value::Time(time) => format!(r#""{}""#, time),
343      Value::DateTime(date_time) => format!(r#""{}""#, date_time),
344      Value::DaysAndTimeDuration(dt_duration) => format!(r#""{}""#, dt_duration),
345      Value::YearsAndMonthsDuration(ym_duration) => format!(r#""{}""#, ym_duration),
346      Value::ExpressionList(items) => values_to_jsonify(items),
347      Value::Context(ctx) => ctx.jsonify(),
348      Value::ContextEntryKey(name) => name.to_string(),
349      Value::List(items) => values_to_jsonify(items),
350      range @ Value::Range(..) => format!(r#""{}""#, range),
351      Value::Null(message) => {
352        if let Some(details) = message {
353          format!(r#""null({details})""#)
354        } else {
355          "null".to_string()
356        }
357      }
358      _ => format!("jsonify trait not implemented for value: {self}"),
359    }
360  }
361}
362
363impl Value {
364  /// Returns `true` when the value is of type [Value::Null].
365  pub fn is_null(&self) -> bool {
366    matches!(self, Value::Null(_))
367  }
368
369  /// Returns `true` when the value is of type [Value::Boolean] and is equal to `true`.
370  pub fn is_true(&self) -> bool {
371    matches!(self, Value::Boolean(true))
372  }
373
374  /// Returns `true` when the value is of type [Value::Boolean] and is equal to `false`.
375  pub fn is_false(&self) -> bool {
376    matches!(self, Value::Boolean(false))
377  }
378
379  /// Returns `true` when the value is of type [Value::Number].
380  pub fn is_number(&self) -> bool {
381    matches!(self, Value::Number(_))
382  }
383
384  /// Returns `true` when the value is of type [Value::String].
385  pub fn is_string(&self) -> bool {
386    matches!(self, Value::String(_))
387  }
388
389  /// Returns `true` when the value is of type [Value::List].
390  pub fn is_list(&self) -> bool {
391    matches!(self, Value::List(_))
392  }
393
394  /// Returns `true` when the value is of type [Value::Range].
395  pub fn is_range(&self) -> bool {
396    matches!(self, Value::Range(_, _, _, _))
397  }
398
399  /// Returns `true` when the value is a valid range.
400  pub fn is_valid_range(&self) -> bool {
401    if let Value::Range(start, start_closed, end, end_closed) = self {
402      match start.borrow() {
403        Value::String(start) => match end.borrow() {
404          Value::String(end) => start <= end,
405          Value::Null(_) => !*end_closed,
406          _ => false,
407        },
408        Value::Number(start) => match end.borrow() {
409          Value::Number(end) => start <= end,
410          Value::Null(_) => !*end_closed,
411          _ => false,
412        },
413        Value::Date(start) => match end.borrow() {
414          Value::Date(end) => start <= end,
415          Value::Null(_) => !*end_closed,
416          _ => false,
417        },
418        Value::DateTime(start) => match end.borrow() {
419          Value::DateTime(end) => start <= end,
420          Value::Null(_) => !*end_closed,
421          _ => false,
422        },
423        Value::Time(start) => match end.borrow() {
424          Value::Time(end) => start <= end,
425          Value::Null(_) => !*end_closed,
426          _ => false,
427        },
428        Value::YearsAndMonthsDuration(start) => match end.borrow() {
429          Value::YearsAndMonthsDuration(end) => start <= end,
430          Value::Null(_) => !*end_closed,
431          _ => false,
432        },
433        Value::DaysAndTimeDuration(start) => match end.borrow() {
434          Value::DaysAndTimeDuration(end) => start <= end,
435          Value::Null(_) => !*end_closed,
436          _ => false,
437        },
438        Value::Null(_) => match end.borrow() {
439          Value::Null(_) => false,
440          _ => !*start_closed,
441        },
442        _ => false,
443      }
444    } else {
445      false
446    }
447  }
448
449  /// Returns `true` when the value is of type [Value::Null] indicating invalid coercion.
450  pub fn is_invalid_coercion(&self) -> bool {
451    if let Value::Null(Some(message)) = self {
452      message == INVALID_COERCION
453    } else {
454      false
455    }
456  }
457
458  /// Returns the type of this [Value].
459  pub fn type_of(&self) -> FeelType {
460    match self {
461      Value::Boolean(_) => FeelType::Boolean,
462      Value::BuiltInFunction(_) => FeelType::Any,
463      Value::Context(context) => {
464        let mut entries = BTreeMap::new();
465        for (name, value) in context.deref() {
466          entries.insert(name.clone(), value.type_of());
467        }
468        FeelType::Context(entries)
469      }
470      Value::ContextEntry(_, _) => FeelType::Any,
471      Value::ContextEntryKey(_) => FeelType::Any,
472      Value::ContextType(feel_type) => feel_type.clone(),
473      Value::ContextTypeEntry(_, feel_type) => feel_type.clone(),
474      Value::ContextTypeEntryKey(_) => FeelType::Any,
475      Value::Date(_) => FeelType::Date,
476      Value::DateTime(_) => FeelType::DateTime,
477      Value::DaysAndTimeDuration(_) => FeelType::DaysAndTimeDuration,
478      Value::ExpressionList(_) => FeelType::Any,
479      Value::ExternalJavaFunction(_, _) => FeelType::Any,
480      Value::ExternalPmmlFunction(_, _) => FeelType::Any,
481      Value::FeelType(feel_type) => feel_type.clone(),
482      Value::FormalParameter(_, feel_type) => feel_type.clone(),
483      Value::FormalParameters(_) => FeelType::Any,
484      Value::FunctionBody(_, _) => FeelType::Any,
485      Value::FunctionDefinition(parameters, _, _, _, _, result_type) => {
486        let parameter_types = parameters.iter().map(|(_, feel_type)| feel_type.clone()).collect();
487        FeelType::Function(parameter_types, Box::new(result_type.clone()))
488      }
489      Value::IntervalEnd(interval_end, _) => interval_end.type_of(),
490      Value::IntervalStart(interval_start, _) => interval_start.type_of(),
491      Value::Irrelevant => FeelType::Any,
492      Value::List(values) => {
493        if values.is_empty() {
494          FeelType::List(Box::new(FeelType::Null))
495        } else {
496          let item_type = values[0].type_of();
497          for item in values {
498            if !item.type_of().is_conformant(&item_type) {
499              return FeelType::List(Box::new(FeelType::Any));
500            }
501          }
502          FeelType::List(Box::new(item_type))
503        }
504      }
505      Value::NamedParameter(_, _) => FeelType::Any,
506      Value::NamedParameters(_) => FeelType::Any,
507      Value::NegatedCommaList(_) => FeelType::Any,
508      Value::Null(_) => FeelType::Null,
509      Value::Number(_) => FeelType::Number,
510      Value::ParameterName(_) => FeelType::Any,
511      Value::ParameterTypes(_) => FeelType::Any,
512      Value::PositionalParameters(_) => FeelType::Any,
513      Value::QualifiedNameSegment(_) => FeelType::Any,
514      Value::Range(range_start, _, range_end, _) => {
515        let range_start_type = range_start.type_of();
516        let range_end_type = range_end.type_of();
517        if range_start_type == range_end_type {
518          return FeelType::Range(Box::new(range_start_type));
519        }
520        FeelType::Range(Box::new(FeelType::Any))
521      }
522      Value::String(_) => FeelType::String,
523      Value::Time(_) => FeelType::Time,
524      Value::UnaryGreater(_) => FeelType::Boolean,
525      Value::UnaryGreaterOrEqual(_) => FeelType::Boolean,
526      Value::UnaryLess(_) => FeelType::Boolean,
527      Value::UnaryLessOrEqual(_) => FeelType::Boolean,
528      Value::UnaryEqual(_) => FeelType::Boolean,
529      Value::UnaryNotEqual(_) => FeelType::Boolean,
530      Value::Transparent(value) => value.type_of(),
531      Value::YearsAndMonthsDuration(_) => FeelType::YearsAndMonthsDuration,
532    }
533  }
534
535  /// Checks if a value is conformant with specified target type.
536  pub fn is_conformant(&self, target_type: &FeelType) -> bool {
537    if matches!(target_type, FeelType::Any) {
538      return true;
539    }
540    match self {
541      Value::Null(_) => true,
542      Value::Boolean(_) => matches!(target_type, FeelType::Boolean),
543      Value::Number(_) => matches!(target_type, FeelType::Number),
544      Value::String(_) => matches!(target_type, FeelType::String),
545      Value::Date(_) => matches!(target_type, FeelType::Date),
546      Value::Time(_) => matches!(target_type, FeelType::Time),
547      Value::DateTime(_) => matches!(target_type, FeelType::DateTime),
548      Value::DaysAndTimeDuration(_) => matches!(target_type, FeelType::DaysAndTimeDuration),
549      Value::YearsAndMonthsDuration(_) => matches!(target_type, FeelType::YearsAndMonthsDuration),
550      Value::Range(r_start, _, r_end, _) => {
551        if let FeelType::Range(range_type) = target_type {
552          return r_start.is_conformant(range_type) && r_end.is_conformant(range_type);
553        }
554        false
555      }
556      Value::List(items) => {
557        if let FeelType::List(list_type) = target_type {
558          for item in items {
559            if !item.is_conformant(list_type) {
560              return false;
561            }
562          }
563          return true;
564        }
565        false
566      }
567      Value::Context(context) => {
568        if let FeelType::Context(type_context) = target_type {
569          for (name, entry_type) in type_context.iter() {
570            if let Some(entry_value) = context.get(name) {
571              if !entry_value.is_conformant(entry_type) {
572                return false;
573              }
574            } else {
575              return false;
576            }
577          }
578          return true;
579        }
580        false
581      }
582      Value::FunctionDefinition(parameters, _, _, _, _, result_type) => {
583        if let FeelType::Function(t_parameters, t_result) = target_type {
584          if parameters.len() != t_parameters.len() {
585            return false;
586          }
587          if !result_type.is_conformant(t_result) {
588            return false;
589          }
590          for (i, (_, parameter_type)) in parameters.iter().enumerate() {
591            if !parameter_type.is_conformant(&t_parameters[i]) {
592              return false;
593            }
594          }
595          return true;
596        }
597        false
598      }
599      _ => false,
600    }
601  }
602
603  /// Returns value coerced to specified type.
604  /// When a value appears in a certain context, it must be compatible
605  /// with a type expected in that context, called the target type.
606  /// After the type of the value is known, an implicit conversion
607  /// from the type of the value to the target type can be performed.
608  /// If an implicit conversion is mandatory but it cannot be performed,
609  /// the result is null.
610  ///
611  /// There are several possible type conversions:
612  ///
613  /// - to singleton list:
614  ///
615  ///  When the type of the value is `T` and the target type is `List<T>`,
616  ///  the simple value is converted to a singleton list.
617  ///
618  /// - from singleton list:
619  ///
620  ///  When the type of the value is `List<T>`, and the value is a singleton list
621  ///  and the target type is T, the value is converted by unwrapping the first element.
622  ///
623  /// - conforms to:
624  ///
625  ///  When the type of the value is T1, the target type is T2, and T1 conforms to T2,
626  ///  the value remains unchanged, otherwise the result is null.
627  ///
628  /// All these conversion rules are implemented in this function.
629  ///
630  pub fn coerced(&self, target_type: &FeelType) -> Value {
631    if let Value::FunctionDefinition(_, _, _, _, _, _) = self {
632      return self.clone();
633    }
634    if let Value::BuiltInFunction(bif) = self {
635      if bif.feel_type().is_conformant(target_type) {
636        return self.clone();
637      }
638    }
639    if self.is_conformant(target_type) {
640      return self.clone();
641    }
642    match self {
643      // from singleton list
644      Value::List(items) => {
645        if items.len() == 1 {
646          let value = items[0].clone();
647          if value.is_conformant(target_type) {
648            return value;
649          }
650        }
651      }
652      // to singleton list
653      value => {
654        if let FeelType::List(list_type) = target_type {
655          if value.is_conformant(list_type) {
656            return Value::List(vec![value.clone()]);
657          }
658        }
659      }
660    }
661    value_null!(INVALID_COERCION)
662  }
663
664  /// Tries to convert `xsd:integer` string into valid [Value] representing a number.
665  pub fn try_from_xsd_integer(text: &str) -> Result<Self> {
666    let value = text.parse::<FeelNumber>().map_err(|_| err_invalid_xsd_integer(text))?;
667    Ok(Value::Number(value))
668  }
669
670  /// Tries to convert `xsd:decimal` string into valid [Value] representing a number.
671  pub fn try_from_xsd_decimal(text: &str) -> Result<Self> {
672    let value = text.parse::<FeelNumber>().map_err(|_| err_invalid_xsd_decimal(text))?;
673    Ok(Value::Number(value))
674  }
675
676  /// Tries to convert `xsd:double` string into valid [Value] representing a number.
677  pub fn try_from_xsd_double(text: &str) -> Result<Self> {
678    let value = text.parse::<FeelNumber>().map_err(|_| err_invalid_xsd_double(text))?;
679    Ok(Value::Number(value))
680  }
681
682  /// Tries to convert `xsd:boolean` string into valid [Value] representing a boolean.
683  pub fn try_from_xsd_boolean(text: &str) -> Result<Self> {
684    match text {
685      "true" | "1" => Ok(Value::Boolean(true)),
686      "false" | "0" => Ok(Value::Boolean(false)),
687      _ => Err(err_invalid_xsd_boolean(text)),
688    }
689  }
690
691  /// Tries to convert `xsd:date` string into valid [Value] representing a date.
692  /// FEEL date format is fully conformant with `xsd:date`.
693  pub fn try_from_xsd_date(text: &str) -> Result<Self> {
694    if let Ok(feel_date) = FeelDate::from_str(text) {
695      return Ok(Value::Date(feel_date));
696    }
697    Err(err_invalid_xsd_date(text))
698  }
699
700  /// Tries to convert `xsd:time` string into valid [Value] representing a time.
701  /// FEEL time format is fully conformant with `xsd:time`.
702  pub fn try_from_xsd_time(text: &str) -> Result<Self> {
703    if let Ok(feel_time) = FeelTime::from_str(text) {
704      return Ok(Value::Time(feel_time));
705    }
706    Err(err_invalid_xsd_time(text))
707  }
708
709  /// Tries to convert `xsd:dateTime` string into valid [Value] representing a date and time.
710  /// FEEL date and time format is fully conformant with `xsd:dateTime`.
711  pub fn try_from_xsd_date_time(text: &str) -> Result<Self> {
712    Ok(Value::DateTime(FeelDateTime::try_from(text).map_err(|_| err_invalid_xsd_date_time(text))?))
713  }
714
715  /// Tries to convert `xsd:duration` string into valid [Value] representing a date and time.
716  /// FEEL durations are conformant with `xsd:duration` but spit into two ranges.
717  pub fn try_from_xsd_duration(text: &str) -> Result<Self> {
718    if let Ok(ym_duration) = FeelYearsAndMonthsDuration::try_from(text) {
719      return Ok(Value::YearsAndMonthsDuration(ym_duration));
720    }
721    if let Ok(dt_duration) = FeelDaysAndTimeDuration::try_from(text) {
722      return Ok(Value::DaysAndTimeDuration(dt_duration));
723    }
724    Err(err_invalid_xsd_duration(text))
725  }
726}
727
728/// Type alias to a collection of values.
729pub type Values = Vec<Value>;
730
731/// Converts a collection of values into string.
732pub fn values_to_string(values: &Values) -> String {
733  format!("[{}]", values.iter().map(|value| value.to_string()).collect::<Vec<String>>().join(", "))
734}
735
736/// Converts a collection of values into `FEEL` string.
737pub fn values_to_feel_string(values: &Values) -> String {
738  format!("[{}]", values.iter().map(|value| value.to_feel_string()).collect::<Vec<String>>().join(", "))
739}
740
741/// Converts a collection of values into `JSON` string.
742pub fn values_to_jsonify(values: &Values) -> String {
743  format!("[{}]", values.iter().map(|value| value.jsonify()).collect::<Vec<String>>().join(", "))
744}