wdl_engine/
value.rs

1//! Implementation of the WDL runtime and values.
2
3use std::cmp::Ordering;
4use std::fmt;
5use std::hash::Hash;
6use std::hash::Hasher;
7use std::path::Path;
8use std::sync::Arc;
9
10use anyhow::Context;
11use anyhow::Result;
12use anyhow::anyhow;
13use anyhow::bail;
14use indexmap::IndexMap;
15use itertools::Either;
16use ordered_float::OrderedFloat;
17use serde::ser::SerializeMap;
18use serde::ser::SerializeSeq;
19use wdl_analysis::stdlib::STDLIB as ANALYSIS_STDLIB;
20use wdl_analysis::types::ArrayType;
21use wdl_analysis::types::CallType;
22use wdl_analysis::types::Coercible as _;
23use wdl_analysis::types::CompoundType;
24use wdl_analysis::types::Optional;
25use wdl_analysis::types::PrimitiveType;
26use wdl_analysis::types::Type;
27use wdl_ast::AstToken;
28use wdl_ast::TreeNode;
29use wdl_ast::v1;
30use wdl_ast::v1::TASK_FIELD_ATTEMPT;
31use wdl_ast::v1::TASK_FIELD_CONTAINER;
32use wdl_ast::v1::TASK_FIELD_CPU;
33use wdl_ast::v1::TASK_FIELD_DISKS;
34use wdl_ast::v1::TASK_FIELD_END_TIME;
35use wdl_ast::v1::TASK_FIELD_EXT;
36use wdl_ast::v1::TASK_FIELD_FPGA;
37use wdl_ast::v1::TASK_FIELD_GPU;
38use wdl_ast::v1::TASK_FIELD_ID;
39use wdl_ast::v1::TASK_FIELD_MEMORY;
40use wdl_ast::v1::TASK_FIELD_META;
41use wdl_ast::v1::TASK_FIELD_NAME;
42use wdl_ast::v1::TASK_FIELD_PARAMETER_META;
43use wdl_ast::v1::TASK_FIELD_RETURN_CODE;
44use wdl_grammar::lexer::v1::is_ident;
45
46use crate::EvaluationContext;
47use crate::Outputs;
48use crate::TaskExecutionConstraints;
49use crate::path;
50
51/// Implemented on coercible values.
52pub trait Coercible: Sized {
53    /// Coerces the value into the given type.
54    ///
55    /// Returns an error if the coercion is not supported.
56    fn coerce(&self, target: &Type) -> Result<Self>;
57}
58
59/// Represents a WDL runtime value.
60///
61/// Values are cheap to clone.
62#[derive(Debug, Clone)]
63pub enum Value {
64    /// The value is a literal `None` value.
65    None,
66    /// The value is a primitive value.
67    Primitive(PrimitiveValue),
68    /// The value is a compound value.
69    Compound(CompoundValue),
70    /// The value is a task variable.
71    ///
72    /// This value occurs only during command and output section evaluation in
73    /// WDL 1.2 tasks.
74    Task(TaskValue),
75    /// The value is a hints value.
76    ///
77    /// Hints values only appear in a task hints section in WDL 1.2.
78    Hints(HintsValue),
79    /// The value is an input value.
80    ///
81    /// Input values only appear in a task hints section in WDL 1.2.
82    Input(InputValue),
83    /// The value is an output value.
84    ///
85    /// Output values only appear in a task hints section in WDL 1.2.
86    Output(OutputValue),
87    /// The value is the outputs of a call.
88    Call(CallValue),
89}
90
91impl Value {
92    /// Creates an object from an iterator of V1 AST metadata items.
93    ///
94    /// # Panics
95    ///
96    /// Panics if the metadata value contains an invalid numeric value.
97    pub fn from_v1_metadata<N: TreeNode>(value: &v1::MetadataValue<N>) -> Self {
98        match value {
99            v1::MetadataValue::Boolean(v) => v.value().into(),
100            v1::MetadataValue::Integer(v) => v.value().expect("number should be in range").into(),
101            v1::MetadataValue::Float(v) => v.value().expect("number should be in range").into(),
102            v1::MetadataValue::String(v) => PrimitiveValue::new_string(
103                v.text()
104                    .expect("metadata strings shouldn't have placeholders")
105                    .text(),
106            )
107            .into(),
108            v1::MetadataValue::Null(_) => Self::None,
109            v1::MetadataValue::Object(o) => Object::from_v1_metadata(o.items()).into(),
110            v1::MetadataValue::Array(a) => Array::new_unchecked(
111                ANALYSIS_STDLIB.array_object_type().clone(),
112                a.elements().map(|v| Value::from_v1_metadata(&v)).collect(),
113            )
114            .into(),
115        }
116    }
117
118    /// Gets the type of the value.
119    pub fn ty(&self) -> Type {
120        match self {
121            Self::None => Type::None,
122            Self::Primitive(v) => v.ty(),
123            Self::Compound(v) => v.ty(),
124            Self::Task(_) => Type::Task,
125            Self::Hints(_) => Type::Hints,
126            Self::Input(_) => Type::Input,
127            Self::Output(_) => Type::Output,
128            Self::Call(v) => Type::Call(v.ty.clone()),
129        }
130    }
131
132    /// Determines if the value is `None`.
133    pub fn is_none(&self) -> bool {
134        matches!(self, Self::None)
135    }
136
137    /// Gets the value as a primitive value.
138    ///
139    /// Returns `None` if the value is not a primitive value.
140    pub fn as_primitive(&self) -> Option<&PrimitiveValue> {
141        match self {
142            Self::Primitive(v) => Some(v),
143            _ => None,
144        }
145    }
146
147    /// Gets the value as a compound value.
148    ///
149    /// Returns `None` if the value is not a compound value.
150    pub fn as_compound(&self) -> Option<&CompoundValue> {
151        match self {
152            Self::Compound(v) => Some(v),
153            _ => None,
154        }
155    }
156
157    /// Gets the value as a `Boolean`.
158    ///
159    /// Returns `None` if the value is not a `Boolean`.
160    pub fn as_boolean(&self) -> Option<bool> {
161        match self {
162            Self::Primitive(PrimitiveValue::Boolean(v)) => Some(*v),
163            _ => None,
164        }
165    }
166
167    /// Unwraps the value into a `Boolean`.
168    ///
169    /// # Panics
170    ///
171    /// Panics if the value is not a `Boolean`.
172    pub fn unwrap_boolean(self) -> bool {
173        match self {
174            Self::Primitive(PrimitiveValue::Boolean(v)) => v,
175            _ => panic!("value is not a boolean"),
176        }
177    }
178
179    /// Gets the value as an `Int`.
180    ///
181    /// Returns `None` if the value is not an `Int`.
182    pub fn as_integer(&self) -> Option<i64> {
183        match self {
184            Self::Primitive(PrimitiveValue::Integer(v)) => Some(*v),
185            _ => None,
186        }
187    }
188
189    /// Unwraps the value into an integer.
190    ///
191    /// # Panics
192    ///
193    /// Panics if the value is not an integer.
194    pub fn unwrap_integer(self) -> i64 {
195        match self {
196            Self::Primitive(PrimitiveValue::Integer(v)) => v,
197            _ => panic!("value is not an integer"),
198        }
199    }
200
201    /// Gets the value as a `Float`.
202    ///
203    /// Returns `None` if the value is not a `Float`.
204    pub fn as_float(&self) -> Option<f64> {
205        match self {
206            Self::Primitive(PrimitiveValue::Float(v)) => Some((*v).into()),
207            _ => None,
208        }
209    }
210
211    /// Unwraps the value into a `Float`.
212    ///
213    /// # Panics
214    ///
215    /// Panics if the value is not a `Float`.
216    pub fn unwrap_float(self) -> f64 {
217        match self {
218            Self::Primitive(PrimitiveValue::Float(v)) => v.into(),
219            _ => panic!("value is not a float"),
220        }
221    }
222
223    /// Gets the value as a `String`.
224    ///
225    /// Returns `None` if the value is not a `String`.
226    pub fn as_string(&self) -> Option<&Arc<String>> {
227        match self {
228            Self::Primitive(PrimitiveValue::String(s)) => Some(s),
229            _ => None,
230        }
231    }
232
233    /// Unwraps the value into a `String`.
234    ///
235    /// # Panics
236    ///
237    /// Panics if the value is not a `String`.
238    pub fn unwrap_string(self) -> Arc<String> {
239        match self {
240            Self::Primitive(PrimitiveValue::String(s)) => s,
241            _ => panic!("value is not a string"),
242        }
243    }
244
245    /// Gets the value as a `File`.
246    ///
247    /// Returns `None` if the value is not a `File`.
248    pub fn as_file(&self) -> Option<&Arc<String>> {
249        match self {
250            Self::Primitive(PrimitiveValue::File(s)) => Some(s),
251            _ => None,
252        }
253    }
254
255    /// Unwraps the value into a `File`.
256    ///
257    /// # Panics
258    ///
259    /// Panics if the value is not a `File`.
260    pub fn unwrap_file(self) -> Arc<String> {
261        match self {
262            Self::Primitive(PrimitiveValue::File(s)) => s,
263            _ => panic!("value is not a file"),
264        }
265    }
266
267    /// Gets the value as a `Directory`.
268    ///
269    /// Returns `None` if the value is not a `Directory`.
270    pub fn as_directory(&self) -> Option<&Arc<String>> {
271        match self {
272            Self::Primitive(PrimitiveValue::Directory(s)) => Some(s),
273            _ => None,
274        }
275    }
276
277    /// Unwraps the value into a `Directory`.
278    ///
279    /// # Panics
280    ///
281    /// Panics if the value is not a `Directory`.
282    pub fn unwrap_directory(self) -> Arc<String> {
283        match self {
284            Self::Primitive(PrimitiveValue::Directory(s)) => s,
285            _ => panic!("value is not a directory"),
286        }
287    }
288
289    /// Gets the value as a `Pair`.
290    ///
291    /// Returns `None` if the value is not a `Pair`.
292    pub fn as_pair(&self) -> Option<&Pair> {
293        match self {
294            Self::Compound(CompoundValue::Pair(v)) => Some(v),
295            _ => None,
296        }
297    }
298
299    /// Unwraps the value into a `Pair`.
300    ///
301    /// # Panics
302    ///
303    /// Panics if the value is not a `Pair`.
304    pub fn unwrap_pair(self) -> Pair {
305        match self {
306            Self::Compound(CompoundValue::Pair(v)) => v,
307            _ => panic!("value is not a pair"),
308        }
309    }
310
311    /// Gets the value as an `Array`.
312    ///
313    /// Returns `None` if the value is not an `Array`.
314    pub fn as_array(&self) -> Option<&Array> {
315        match self {
316            Self::Compound(CompoundValue::Array(v)) => Some(v),
317            _ => None,
318        }
319    }
320
321    /// Unwraps the value into an `Array`.
322    ///
323    /// # Panics
324    ///
325    /// Panics if the value is not an `Array`.
326    pub fn unwrap_array(self) -> Array {
327        match self {
328            Self::Compound(CompoundValue::Array(v)) => v,
329            _ => panic!("value is not an array"),
330        }
331    }
332
333    /// Gets the value as a `Map`.
334    ///
335    /// Returns `None` if the value is not a `Map`.
336    pub fn as_map(&self) -> Option<&Map> {
337        match self {
338            Self::Compound(CompoundValue::Map(v)) => Some(v),
339            _ => None,
340        }
341    }
342
343    /// Unwraps the value into a `Map`.
344    ///
345    /// # Panics
346    ///
347    /// Panics if the value is not a `Map`.
348    pub fn unwrap_map(self) -> Map {
349        match self {
350            Self::Compound(CompoundValue::Map(v)) => v,
351            _ => panic!("value is not a map"),
352        }
353    }
354
355    /// Gets the value as an `Object`.
356    ///
357    /// Returns `None` if the value is not an `Object`.
358    pub fn as_object(&self) -> Option<&Object> {
359        match self {
360            Self::Compound(CompoundValue::Object(v)) => Some(v),
361            _ => None,
362        }
363    }
364
365    /// Unwraps the value into an `Object`.
366    ///
367    /// # Panics
368    ///
369    /// Panics if the value is not an `Object`.
370    pub fn unwrap_object(self) -> Object {
371        match self {
372            Self::Compound(CompoundValue::Object(v)) => v,
373            _ => panic!("value is not an object"),
374        }
375    }
376
377    /// Gets the value as a `Struct`.
378    ///
379    /// Returns `None` if the value is not a `Struct`.
380    pub fn as_struct(&self) -> Option<&Struct> {
381        match self {
382            Self::Compound(CompoundValue::Struct(v)) => Some(v),
383            _ => None,
384        }
385    }
386
387    /// Unwraps the value into a `Struct`.
388    ///
389    /// # Panics
390    ///
391    /// Panics if the value is not a `Map`.
392    pub fn unwrap_struct(self) -> Struct {
393        match self {
394            Self::Compound(CompoundValue::Struct(v)) => v,
395            _ => panic!("value is not a struct"),
396        }
397    }
398
399    /// Gets the value as a task.
400    ///
401    /// Returns `None` if the value is not a task.
402    pub fn as_task(&self) -> Option<&TaskValue> {
403        match self {
404            Self::Task(v) => Some(v),
405            _ => None,
406        }
407    }
408
409    /// Gets a mutable reference to the value as a task.
410    ///
411    /// Returns `None` if the value is not a task.
412    pub(crate) fn as_task_mut(&mut self) -> Option<&mut TaskValue> {
413        match self {
414            Self::Task(v) => Some(v),
415            _ => None,
416        }
417    }
418
419    /// Unwraps the value into a task.
420    ///
421    /// # Panics
422    ///
423    /// Panics if the value is not a task.
424    pub fn unwrap_task(self) -> TaskValue {
425        match self {
426            Self::Task(v) => v,
427            _ => panic!("value is not a task"),
428        }
429    }
430
431    /// Gets the value as a hints value.
432    ///
433    /// Returns `None` if the value is not a hints value.
434    pub fn as_hints(&self) -> Option<&HintsValue> {
435        match self {
436            Self::Hints(v) => Some(v),
437            _ => None,
438        }
439    }
440
441    /// Unwraps the value into a hints value.
442    ///
443    /// # Panics
444    ///
445    /// Panics if the value is not a hints value.
446    pub fn unwrap_hints(self) -> HintsValue {
447        match self {
448            Self::Hints(v) => v,
449            _ => panic!("value is not a hints value"),
450        }
451    }
452
453    /// Gets the value as a call value.
454    ///
455    /// Returns `None` if the value is not a call value.
456    pub fn as_call(&self) -> Option<&CallValue> {
457        match self {
458            Self::Call(v) => Some(v),
459            _ => None,
460        }
461    }
462
463    /// Unwraps the value into a call value.
464    ///
465    /// # Panics
466    ///
467    /// Panics if the value is not a call value.
468    pub fn unwrap_call(self) -> CallValue {
469        match self {
470            Self::Call(v) => v,
471            _ => panic!("value is not a call value"),
472        }
473    }
474
475    /// Visits each `File` or `Directory` value contained in this value.
476    ///
477    /// Note that paths may be specified as URLs.
478    pub(crate) fn visit_paths(
479        &self,
480        optional: bool,
481        cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>,
482    ) -> Result<()> {
483        match self {
484            Self::Primitive(v) => v.visit_paths(optional, cb),
485            Self::Compound(v) => v.visit_paths(cb),
486            _ => Ok(()),
487        }
488    }
489
490    /// Mutably visits each `File` or `Directory` value contained in this value.
491    ///
492    /// If the provided callback returns `Ok(false)`, the `File` or `Directory`
493    /// value will be replaced with `None`.
494    ///
495    /// Note that paths may be specified as URLs.
496    pub(crate) fn visit_paths_mut(
497        &mut self,
498        optional: bool,
499        cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
500    ) -> Result<()> {
501        match self {
502            Self::Primitive(v) => {
503                if !v.visit_paths_mut(optional, cb)? {
504                    *self = Value::None;
505                }
506
507                Ok(())
508            }
509            Self::Compound(v) => v.visit_paths_mut(cb),
510            _ => Ok(()),
511        }
512    }
513
514    /// Creates a clone of the value, but makes the type required.
515    ///
516    /// This only affects compound values that internally store their type.
517    pub(crate) fn clone_as_required(&self) -> Self {
518        match self {
519            Self::Compound(v) => Self::Compound(v.clone_as_required()),
520            _ => self.clone(),
521        }
522    }
523
524    /// Creates a clone of the value, but makes the type optional.
525    ///
526    /// This only affects compound values that internally store their type.
527    pub(crate) fn clone_as_optional(&self) -> Self {
528        match self {
529            Self::Compound(v) => Self::Compound(v.clone_as_optional()),
530            _ => self.clone(),
531        }
532    }
533
534    /// Determines if two values have equality according to the WDL
535    /// specification.
536    ///
537    /// Returns `None` if the two values cannot be compared for equality.
538    pub fn equals(left: &Self, right: &Self) -> Option<bool> {
539        match (left, right) {
540            (Value::None, Value::None) => Some(true),
541            (Value::None, _) | (_, Value::None) => Some(false),
542            (Value::Primitive(left), Value::Primitive(right)) => {
543                Some(PrimitiveValue::compare(left, right)? == Ordering::Equal)
544            }
545            (Value::Compound(left), Value::Compound(right)) => CompoundValue::equals(left, right),
546            _ => None,
547        }
548    }
549}
550
551impl fmt::Display for Value {
552    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553        match self {
554            Self::None => write!(f, "None"),
555            Self::Primitive(v) => v.fmt(f),
556            Self::Compound(v) => v.fmt(f),
557            Self::Task(_) => write!(f, "task"),
558            Self::Hints(v) => v.fmt(f),
559            Self::Input(v) => v.fmt(f),
560            Self::Output(v) => v.fmt(f),
561            Self::Call(c) => c.fmt(f),
562        }
563    }
564}
565
566impl Coercible for Value {
567    fn coerce(&self, target: &Type) -> Result<Self> {
568        if target.is_union() || target.is_none() || self.ty().eq(target) {
569            return Ok(self.clone());
570        }
571
572        match self {
573            Self::None => {
574                if target.is_optional() {
575                    Ok(Self::None)
576                } else {
577                    bail!("cannot coerce `None` to non-optional type `{target}`");
578                }
579            }
580            Self::Primitive(v) => v.coerce(target).map(Self::Primitive),
581            Self::Compound(v) => v.coerce(target).map(Self::Compound),
582            Self::Task(_) => {
583                if matches!(target, Type::Task) {
584                    return Ok(self.clone());
585                }
586
587                bail!("task variables cannot be coerced to any other type");
588            }
589            Self::Hints(_) => {
590                if matches!(target, Type::Hints) {
591                    return Ok(self.clone());
592                }
593
594                bail!("hints values cannot be coerced to any other type");
595            }
596            Self::Input(_) => {
597                if matches!(target, Type::Input) {
598                    return Ok(self.clone());
599                }
600
601                bail!("input values cannot be coerced to any other type");
602            }
603            Self::Output(_) => {
604                if matches!(target, Type::Output) {
605                    return Ok(self.clone());
606                }
607
608                bail!("output values cannot be coerced to any other type");
609            }
610            Self::Call(_) => {
611                bail!("call values cannot be coerced to any other type");
612            }
613        }
614    }
615}
616
617impl From<bool> for Value {
618    fn from(value: bool) -> Self {
619        Self::Primitive(value.into())
620    }
621}
622
623impl From<i64> for Value {
624    fn from(value: i64) -> Self {
625        Self::Primitive(value.into())
626    }
627}
628
629impl TryFrom<u64> for Value {
630    type Error = std::num::TryFromIntError;
631
632    fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
633        let value: i64 = value.try_into()?;
634        Ok(value.into())
635    }
636}
637
638impl From<f64> for Value {
639    fn from(value: f64) -> Self {
640        Self::Primitive(value.into())
641    }
642}
643
644impl From<String> for Value {
645    fn from(value: String) -> Self {
646        Self::Primitive(value.into())
647    }
648}
649
650impl From<PrimitiveValue> for Value {
651    fn from(value: PrimitiveValue) -> Self {
652        Self::Primitive(value)
653    }
654}
655
656impl From<Option<PrimitiveValue>> for Value {
657    fn from(value: Option<PrimitiveValue>) -> Self {
658        match value {
659            Some(v) => v.into(),
660            None => Self::None,
661        }
662    }
663}
664
665impl From<CompoundValue> for Value {
666    fn from(value: CompoundValue) -> Self {
667        Self::Compound(value)
668    }
669}
670
671impl From<Pair> for Value {
672    fn from(value: Pair) -> Self {
673        Self::Compound(value.into())
674    }
675}
676
677impl From<Array> for Value {
678    fn from(value: Array) -> Self {
679        Self::Compound(value.into())
680    }
681}
682
683impl From<Map> for Value {
684    fn from(value: Map) -> Self {
685        Self::Compound(value.into())
686    }
687}
688
689impl From<Object> for Value {
690    fn from(value: Object) -> Self {
691        Self::Compound(value.into())
692    }
693}
694
695impl From<Struct> for Value {
696    fn from(value: Struct) -> Self {
697        Self::Compound(value.into())
698    }
699}
700
701impl From<TaskValue> for Value {
702    fn from(value: TaskValue) -> Self {
703        Self::Task(value)
704    }
705}
706
707impl From<HintsValue> for Value {
708    fn from(value: HintsValue) -> Self {
709        Self::Hints(value)
710    }
711}
712
713impl From<CallValue> for Value {
714    fn from(value: CallValue) -> Self {
715        Self::Call(value)
716    }
717}
718
719impl serde::Serialize for Value {
720    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
721    where
722        S: serde::Serializer,
723    {
724        use serde::ser::Error;
725
726        match self {
727            Self::None => serializer.serialize_none(),
728            Self::Primitive(v) => v.serialize(serializer),
729            Self::Compound(v) => v.serialize(serializer),
730            Self::Task(_) | Self::Hints(_) | Self::Input(_) | Self::Output(_) | Self::Call(_) => {
731                Err(S::Error::custom("value cannot be serialized"))
732            }
733        }
734    }
735}
736
737impl<'de> serde::Deserialize<'de> for Value {
738    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
739    where
740        D: serde::Deserializer<'de>,
741    {
742        use serde::Deserialize as _;
743
744        /// Helper for deserializing the elements of sequences and maps
745        struct Deserialize;
746
747        impl<'de> serde::de::DeserializeSeed<'de> for Deserialize {
748            type Value = Value;
749
750            fn deserialize<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
751            where
752                D: serde::Deserializer<'de>,
753            {
754                deserializer.deserialize_any(Visitor)
755            }
756        }
757
758        /// Visitor for deserialization.
759        struct Visitor;
760
761        impl<'de> serde::de::Visitor<'de> for Visitor {
762            type Value = Value;
763
764            fn visit_unit<E>(self) -> std::result::Result<Self::Value, E>
765            where
766                E: serde::de::Error,
767            {
768                Ok(Value::None)
769            }
770
771            fn visit_none<E>(self) -> std::result::Result<Self::Value, E>
772            where
773                E: serde::de::Error,
774            {
775                Ok(Value::None)
776            }
777
778            fn visit_some<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
779            where
780                D: serde::Deserializer<'de>,
781            {
782                Value::deserialize(deserializer)
783            }
784
785            fn visit_bool<E>(self, v: bool) -> std::result::Result<Self::Value, E>
786            where
787                E: serde::de::Error,
788            {
789                Ok(Value::Primitive(PrimitiveValue::Boolean(v)))
790            }
791
792            fn visit_i64<E>(self, v: i64) -> std::result::Result<Self::Value, E>
793            where
794                E: serde::de::Error,
795            {
796                Ok(Value::Primitive(PrimitiveValue::Integer(v)))
797            }
798
799            fn visit_u64<E>(self, v: u64) -> std::result::Result<Self::Value, E>
800            where
801                E: serde::de::Error,
802            {
803                Ok(Value::Primitive(PrimitiveValue::Integer(
804                    v.try_into().map_err(|_| {
805                        E::custom("integer not in range for a 64-bit signed integer")
806                    })?,
807                )))
808            }
809
810            fn visit_f64<E>(self, v: f64) -> std::result::Result<Self::Value, E>
811            where
812                E: serde::de::Error,
813            {
814                Ok(Value::Primitive(PrimitiveValue::Float(v.into())))
815            }
816
817            fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
818            where
819                E: serde::de::Error,
820            {
821                Ok(Value::Primitive(PrimitiveValue::new_string(v)))
822            }
823
824            fn visit_string<E>(self, v: String) -> std::result::Result<Self::Value, E>
825            where
826                E: serde::de::Error,
827            {
828                Ok(Value::Primitive(PrimitiveValue::new_string(v)))
829            }
830
831            fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
832            where
833                A: serde::de::SeqAccess<'de>,
834            {
835                use serde::de::Error;
836
837                let mut elements = Vec::new();
838                while let Some(v) = seq.next_element_seed(Deserialize)? {
839                    elements.push(v);
840                }
841
842                let element_ty = elements
843                    .iter()
844                    .try_fold(None, |mut ty, element| {
845                        let element_ty = element.ty();
846                        let ty = ty.get_or_insert(element_ty.clone());
847                        ty.common_type(&element_ty).map(Some).ok_or_else(|| {
848                            A::Error::custom(format!(
849                                "a common element type does not exist between `{ty}` and \
850                                 `{element_ty}`"
851                            ))
852                        })
853                    })?
854                    .unwrap_or(Type::Union);
855
856                let ty: Type = ArrayType::new(element_ty).into();
857                Ok(Array::new(ty.clone(), elements)
858                    .map_err(|e| A::Error::custom(format!("cannot coerce value to `{ty}`: {e:#}")))?
859                    .into())
860            }
861
862            fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
863            where
864                A: serde::de::MapAccess<'de>,
865            {
866                use serde::de::Error;
867
868                let mut members = IndexMap::new();
869                while let Some(key) = map.next_key::<String>()? {
870                    if !is_ident(&key) {
871                        return Err(A::Error::custom(format!(
872                            "object key `{key}` is not a valid WDL identifier"
873                        )));
874                    }
875
876                    members.insert(key, map.next_value_seed(Deserialize)?);
877                }
878
879                Ok(Value::Compound(CompoundValue::Object(Object::new(members))))
880            }
881
882            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
883                write!(f, "a WDL value")
884            }
885        }
886
887        deserializer.deserialize_any(Visitor)
888    }
889}
890
891/// Represents a primitive WDL value.
892///
893/// Primitive values are cheap to clone.
894#[derive(Debug, Clone)]
895pub enum PrimitiveValue {
896    /// The value is a `Boolean`.
897    Boolean(bool),
898    /// The value is an `Int`.
899    Integer(i64),
900    /// The value is a `Float`.
901    Float(OrderedFloat<f64>),
902    /// The value is a `String`.
903    String(Arc<String>),
904    /// The value is a `File`.
905    File(Arc<String>),
906    /// The value is a `Directory`.
907    Directory(Arc<String>),
908}
909
910impl PrimitiveValue {
911    /// Creates a new `String` value.
912    pub fn new_string(s: impl Into<String>) -> Self {
913        Self::String(Arc::new(s.into()))
914    }
915
916    /// Creates a new `File` value.
917    pub fn new_file(s: impl Into<String>) -> Self {
918        Self::File(Arc::new(s.into()))
919    }
920
921    /// Creates a new `Directory` value.
922    pub fn new_directory(s: impl Into<String>) -> Self {
923        Self::Directory(Arc::new(s.into()))
924    }
925
926    /// Gets the type of the value.
927    pub fn ty(&self) -> Type {
928        match self {
929            Self::Boolean(_) => PrimitiveType::Boolean.into(),
930            Self::Integer(_) => PrimitiveType::Integer.into(),
931            Self::Float(_) => PrimitiveType::Float.into(),
932            Self::String(_) => PrimitiveType::String.into(),
933            Self::File(_) => PrimitiveType::File.into(),
934            Self::Directory(_) => PrimitiveType::Directory.into(),
935        }
936    }
937
938    /// Gets the value as a `Boolean`.
939    ///
940    /// Returns `None` if the value is not a `Boolean`.
941    pub fn as_boolean(&self) -> Option<bool> {
942        match self {
943            Self::Boolean(v) => Some(*v),
944            _ => None,
945        }
946    }
947
948    /// Unwraps the value into a `Boolean`.
949    ///
950    /// # Panics
951    ///
952    /// Panics if the value is not a `Boolean`.
953    pub fn unwrap_boolean(self) -> bool {
954        match self {
955            Self::Boolean(v) => v,
956            _ => panic!("value is not a boolean"),
957        }
958    }
959
960    /// Gets the value as an `Int`.
961    ///
962    /// Returns `None` if the value is not an `Int`.
963    pub fn as_integer(&self) -> Option<i64> {
964        match self {
965            Self::Integer(v) => Some(*v),
966            _ => None,
967        }
968    }
969
970    /// Unwraps the value into an integer.
971    ///
972    /// # Panics
973    ///
974    /// Panics if the value is not an integer.
975    pub fn unwrap_integer(self) -> i64 {
976        match self {
977            Self::Integer(v) => v,
978            _ => panic!("value is not an integer"),
979        }
980    }
981
982    /// Gets the value as a `Float`.
983    ///
984    /// Returns `None` if the value is not a `Float`.
985    pub fn as_float(&self) -> Option<f64> {
986        match self {
987            Self::Float(v) => Some((*v).into()),
988            _ => None,
989        }
990    }
991
992    /// Unwraps the value into a `Float`.
993    ///
994    /// # Panics
995    ///
996    /// Panics if the value is not a `Float`.
997    pub fn unwrap_float(self) -> f64 {
998        match self {
999            Self::Float(v) => v.into(),
1000            _ => panic!("value is not a float"),
1001        }
1002    }
1003
1004    /// Gets the value as a `String`.
1005    ///
1006    /// Returns `None` if the value is not a `String`.
1007    pub fn as_string(&self) -> Option<&Arc<String>> {
1008        match self {
1009            Self::String(s) => Some(s),
1010            _ => None,
1011        }
1012    }
1013
1014    /// Unwraps the value into a `String`.
1015    ///
1016    /// # Panics
1017    ///
1018    /// Panics if the value is not a `String`.
1019    pub fn unwrap_string(self) -> Arc<String> {
1020        match self {
1021            Self::String(s) => s,
1022            _ => panic!("value is not a string"),
1023        }
1024    }
1025
1026    /// Gets the value as a `File`.
1027    ///
1028    /// Returns `None` if the value is not a `File`.
1029    pub fn as_file(&self) -> Option<&Arc<String>> {
1030        match self {
1031            Self::File(s) => Some(s),
1032            _ => None,
1033        }
1034    }
1035
1036    /// Unwraps the value into a `File`.
1037    ///
1038    /// # Panics
1039    ///
1040    /// Panics if the value is not a `File`.
1041    pub fn unwrap_file(self) -> Arc<String> {
1042        match self {
1043            Self::File(s) => s,
1044            _ => panic!("value is not a file"),
1045        }
1046    }
1047
1048    /// Gets the value as a `Directory`.
1049    ///
1050    /// Returns `None` if the value is not a `Directory`.
1051    pub fn as_directory(&self) -> Option<&Arc<String>> {
1052        match self {
1053            Self::Directory(s) => Some(s),
1054            _ => None,
1055        }
1056    }
1057
1058    /// Unwraps the value into a `Directory`.
1059    ///
1060    /// # Panics
1061    ///
1062    /// Panics if the value is not a `Directory`.
1063    pub fn unwrap_directory(self) -> Arc<String> {
1064        match self {
1065            Self::Directory(s) => s,
1066            _ => panic!("value is not a directory"),
1067        }
1068    }
1069
1070    /// Compares two values for an ordering according to the WDL specification.
1071    ///
1072    /// Unlike a `PartialOrd` implementation, this takes into account automatic
1073    /// coercions.
1074    ///
1075    /// Returns `None` if the values cannot be compared based on their types.
1076    pub fn compare(left: &Self, right: &Self) -> Option<Ordering> {
1077        match (left, right) {
1078            (Self::Boolean(left), Self::Boolean(right)) => Some(left.cmp(right)),
1079            (Self::Integer(left), Self::Integer(right)) => Some(left.cmp(right)),
1080            (Self::Integer(left), Self::Float(right)) => {
1081                Some(OrderedFloat(*left as f64).cmp(right))
1082            }
1083            (Self::Float(left), Self::Integer(right)) => {
1084                Some(left.cmp(&OrderedFloat(*right as f64)))
1085            }
1086            (Self::Float(left), Self::Float(right)) => Some(left.cmp(right)),
1087            (Self::String(left), Self::String(right))
1088            | (Self::String(left), Self::File(right))
1089            | (Self::String(left), Self::Directory(right))
1090            | (Self::File(left), Self::File(right))
1091            | (Self::File(left), Self::String(right))
1092            | (Self::Directory(left), Self::Directory(right))
1093            | (Self::Directory(left), Self::String(right)) => Some(left.cmp(right)),
1094            _ => None,
1095        }
1096    }
1097
1098    /// Gets a raw display of the value.
1099    ///
1100    /// This differs from the [Display][fmt::Display] implementation in that
1101    /// strings, files, and directories are not quoted and not escaped.
1102    ///
1103    /// If an evaluation context is provided, path translation is attempted.
1104    pub fn raw<'a>(
1105        &'a self,
1106        context: Option<&'a dyn EvaluationContext>,
1107    ) -> impl fmt::Display + use<'a> {
1108        /// Helper for displaying a raw value.
1109        struct Display<'a> {
1110            /// The associated evaluation context.
1111            context: Option<&'a dyn EvaluationContext>,
1112            /// The value to display.
1113            value: &'a PrimitiveValue,
1114        }
1115
1116        impl fmt::Display for Display<'_> {
1117            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1118                match self.value {
1119                    PrimitiveValue::Boolean(v) => write!(f, "{v}"),
1120                    PrimitiveValue::Integer(v) => write!(f, "{v}"),
1121                    PrimitiveValue::Float(v) => write!(f, "{v:.6?}"),
1122                    PrimitiveValue::String(v)
1123                    | PrimitiveValue::File(v)
1124                    | PrimitiveValue::Directory(v) => {
1125                        match self.context.and_then(|c| c.translate_path(v)) {
1126                            Some(path) => write!(f, "{path}", path = path.display()),
1127                            None => {
1128                                write!(f, "{v}")
1129                            }
1130                        }
1131                    }
1132                }
1133            }
1134        }
1135
1136        Display {
1137            context,
1138            value: self,
1139        }
1140    }
1141
1142    /// Visits each `File` or `Directory` value contained in this value.
1143    ///
1144    /// Note that paths may be specified as URLs.
1145    fn visit_paths(
1146        &self,
1147        optional: bool,
1148        cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>,
1149    ) -> Result<()> {
1150        match self {
1151            Self::File(_) | Self::Directory(_) => cb(optional, self),
1152            _ => Ok(()),
1153        }
1154    }
1155
1156    /// Mutably visits each `File` or `Directory` value contained in this value.
1157    ///
1158    /// If the provided callback returns `Ok(false)`, this `File` or `Directory`
1159    /// value will be replaced with `None`.
1160    ///
1161    /// Note that paths may be specified as URLs.
1162    fn visit_paths_mut(
1163        &mut self,
1164        optional: bool,
1165        cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
1166    ) -> Result<bool> {
1167        match self {
1168            Self::File(_) | Self::Directory(_) => cb(optional, self),
1169            _ => Ok(true),
1170        }
1171    }
1172
1173    /// Performs expansions for file and directory paths.
1174    pub(crate) fn expand_path(&mut self) -> Result<()> {
1175        let path = match self {
1176            PrimitiveValue::File(path) => path,
1177            PrimitiveValue::Directory(path) => path,
1178            _ => unreachable!("only file and directory values can be expanded"),
1179        };
1180
1181        let result = shellexpand::full(path.as_str())
1182            .context("expanding file/directory path using shell rules")?;
1183        *Arc::make_mut(path) = result.to_string();
1184
1185        Ok(())
1186    }
1187
1188    /// Joins this path to the given path.
1189    ///
1190    /// # Panics
1191    ///
1192    /// Panics if the value is not a `File` or `Directory`.
1193    pub(crate) fn join_path_to(&mut self, to: &Path) {
1194        let path = match self {
1195            PrimitiveValue::File(path) => path,
1196            PrimitiveValue::Directory(path) => path,
1197            _ => unreachable!("only file and directory values can be joined to a path"),
1198        };
1199
1200        // Don't join URLs
1201        if path::is_url(path) {
1202            return;
1203        }
1204
1205        // Perform the join
1206        if let Ok(s) = to.join(path.as_str()).into_os_string().into_string() {
1207            *Arc::make_mut(path) = s;
1208        }
1209    }
1210
1211    /// Ensures a path value exists on disk.
1212    ///
1213    /// Returns `Ok(true)` if the path exists.
1214    ///
1215    /// Returns `Ok(false)` if the the path does not exist and the type was
1216    /// optional.
1217    ///
1218    /// Otherwise, returns an error if the path does not exist.
1219    ///
1220    /// # Panics
1221    ///
1222    /// Panics if the value is not a `File` or `Directory`.
1223    pub(crate) fn ensure_path_exists(&self, optional: bool) -> Result<bool> {
1224        let (path, is_file) = match self {
1225            PrimitiveValue::File(path) => (path, true),
1226            PrimitiveValue::Directory(path) => (path, false),
1227            _ => unreachable!("only file and directory values should be passed to the callback"),
1228        };
1229
1230        // If it's a file URL, check that the file exists
1231        if path::is_file_url(path) {
1232            let exists = path::parse_url(path)
1233                .and_then(|url| url.to_file_path().ok())
1234                .map(|p| p.exists())
1235                .unwrap_or(false);
1236            if exists {
1237                return Ok(true);
1238            }
1239
1240            if optional && !exists {
1241                return Ok(false);
1242            }
1243
1244            bail!("path `{path}` does not exist");
1245        } else if path::is_url(path) {
1246            // Treat other URLs as they exist
1247            return Ok(true);
1248        }
1249
1250        // Check for existence
1251        let path = Path::new(path.as_str());
1252        if is_file && !path.is_file() {
1253            if optional {
1254                return Ok(false);
1255            }
1256
1257            bail!("file `{path}` does not exist", path = path.display());
1258        } else if !is_file && !path.is_dir() {
1259            if optional {
1260                return Ok(false);
1261            }
1262
1263            bail!("directory `{path}` does not exist", path = path.display())
1264        }
1265
1266        Ok(true)
1267    }
1268}
1269
1270impl fmt::Display for PrimitiveValue {
1271    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1272        match self {
1273            Self::Boolean(v) => write!(f, "{v}"),
1274            Self::Integer(v) => write!(f, "{v}"),
1275            Self::Float(v) => write!(f, "{v:.6?}"),
1276            Self::String(s) | Self::File(s) | Self::Directory(s) => {
1277                // TODO: handle necessary escape sequences
1278                write!(f, "\"{s}\"")
1279            }
1280        }
1281    }
1282}
1283
1284impl PartialEq for PrimitiveValue {
1285    fn eq(&self, other: &Self) -> bool {
1286        Self::compare(self, other) == Some(Ordering::Equal)
1287    }
1288}
1289
1290impl Eq for PrimitiveValue {}
1291
1292impl Hash for PrimitiveValue {
1293    fn hash<H: Hasher>(&self, state: &mut H) {
1294        match self {
1295            Self::Boolean(v) => {
1296                0.hash(state);
1297                v.hash(state);
1298            }
1299            Self::Integer(v) => {
1300                1.hash(state);
1301                v.hash(state);
1302            }
1303            Self::Float(v) => {
1304                // Hash this with the same discriminant as integer; this allows coercion from
1305                // int to float.
1306                1.hash(state);
1307                v.hash(state);
1308            }
1309            Self::String(v) | Self::File(v) | Self::Directory(v) => {
1310                // Hash these with the same discriminant; this allows coercion from file and
1311                // directory to string
1312                2.hash(state);
1313                v.hash(state);
1314            }
1315        }
1316    }
1317}
1318
1319impl From<bool> for PrimitiveValue {
1320    fn from(value: bool) -> Self {
1321        Self::Boolean(value)
1322    }
1323}
1324
1325impl From<i64> for PrimitiveValue {
1326    fn from(value: i64) -> Self {
1327        Self::Integer(value)
1328    }
1329}
1330
1331impl From<f64> for PrimitiveValue {
1332    fn from(value: f64) -> Self {
1333        Self::Float(value.into())
1334    }
1335}
1336
1337impl From<String> for PrimitiveValue {
1338    fn from(value: String) -> Self {
1339        Self::String(value.into())
1340    }
1341}
1342
1343impl Coercible for PrimitiveValue {
1344    fn coerce(&self, target: &Type) -> Result<Self> {
1345        if target.is_union() || target.is_none() || self.ty().eq(target) {
1346            return Ok(self.clone());
1347        }
1348
1349        match self {
1350            Self::Boolean(v) => {
1351                target
1352                    .as_primitive()
1353                    .and_then(|ty| match ty {
1354                        // Boolean -> Boolean
1355                        PrimitiveType::Boolean => Some(Self::Boolean(*v)),
1356                        _ => None,
1357                    })
1358                    .with_context(|| format!("cannot coerce type `Boolean` to type `{target}`"))
1359            }
1360            Self::Integer(v) => {
1361                target
1362                    .as_primitive()
1363                    .and_then(|ty| match ty {
1364                        // Int -> Int
1365                        PrimitiveType::Integer => Some(Self::Integer(*v)),
1366                        // Int -> Float
1367                        PrimitiveType::Float => Some(Self::Float((*v as f64).into())),
1368                        _ => None,
1369                    })
1370                    .with_context(|| format!("cannot coerce type `Int` to type `{target}`"))
1371            }
1372            Self::Float(v) => {
1373                target
1374                    .as_primitive()
1375                    .and_then(|ty| match ty {
1376                        // Float -> Float
1377                        PrimitiveType::Float => Some(Self::Float(*v)),
1378                        _ => None,
1379                    })
1380                    .with_context(|| format!("cannot coerce type `Float` to type `{target}`"))
1381            }
1382            Self::String(s) => {
1383                target
1384                    .as_primitive()
1385                    .and_then(|ty| match ty {
1386                        // String -> String
1387                        PrimitiveType::String => Some(Self::String(s.clone())),
1388                        // String -> File
1389                        PrimitiveType::File => Some(Self::File(s.clone())),
1390                        // String -> Directory
1391                        PrimitiveType::Directory => Some(Self::Directory(s.clone())),
1392                        _ => None,
1393                    })
1394                    .with_context(|| format!("cannot coerce type `String` to type `{target}`"))
1395            }
1396            Self::File(s) => {
1397                target
1398                    .as_primitive()
1399                    .and_then(|ty| match ty {
1400                        // File -> File
1401                        PrimitiveType::File => Some(Self::File(s.clone())),
1402                        // File -> String
1403                        PrimitiveType::String => Some(Self::String(s.clone())),
1404                        _ => None,
1405                    })
1406                    .with_context(|| format!("cannot coerce type `File` to type `{target}`"))
1407            }
1408            Self::Directory(s) => {
1409                target
1410                    .as_primitive()
1411                    .and_then(|ty| match ty {
1412                        // Directory -> Directory
1413                        PrimitiveType::Directory => Some(Self::Directory(s.clone())),
1414                        // Directory -> String
1415                        PrimitiveType::String => Some(Self::String(s.clone())),
1416                        _ => None,
1417                    })
1418                    .with_context(|| format!("cannot coerce type `Directory` to type `{target}`"))
1419            }
1420        }
1421    }
1422}
1423
1424impl serde::Serialize for PrimitiveValue {
1425    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1426    where
1427        S: serde::Serializer,
1428    {
1429        match self {
1430            Self::Boolean(v) => v.serialize(serializer),
1431            Self::Integer(v) => v.serialize(serializer),
1432            Self::Float(v) => v.serialize(serializer),
1433            Self::String(s) | Self::File(s) | Self::Directory(s) => s.serialize(serializer),
1434        }
1435    }
1436}
1437
1438/// Represents a `Pair` value.
1439///
1440/// Pairs are cheap to clone.
1441#[derive(Debug, Clone)]
1442pub struct Pair {
1443    /// The type of the pair.
1444    ty: Type,
1445    /// The left and right values of the pair.
1446    values: Arc<(Value, Value)>,
1447}
1448
1449impl Pair {
1450    /// Creates a new `Pair` value.
1451    ///
1452    /// Returns an error if either the `left` value or the `right` value did not
1453    /// coerce to the pair's `left` type or `right` type, respectively.
1454    ///
1455    /// # Panics
1456    ///
1457    /// Panics if the given type is not a pair type.
1458    pub fn new(
1459        ty: impl Into<Type>,
1460        left: impl Into<Value>,
1461        right: impl Into<Value>,
1462    ) -> Result<Self> {
1463        let ty = ty.into();
1464        if let Type::Compound(CompoundType::Pair(ty), optional) = ty {
1465            let left = left
1466                .into()
1467                .coerce(ty.left_type())
1468                .context("failed to coerce pair's left value")?;
1469            let right = right
1470                .into()
1471                .coerce(ty.right_type())
1472                .context("failed to coerce pair's right value")?;
1473            return Ok(Self::new_unchecked(
1474                Type::Compound(CompoundType::Pair(ty), optional),
1475                left,
1476                right,
1477            ));
1478        }
1479
1480        panic!("type `{ty}` is not a pair type");
1481    }
1482
1483    /// Constructs a new pair without checking the given left and right conform
1484    /// to the given type.
1485    pub(crate) fn new_unchecked(ty: Type, left: Value, right: Value) -> Self {
1486        assert!(ty.as_pair().is_some());
1487        Self {
1488            ty,
1489            values: Arc::new((left, right)),
1490        }
1491    }
1492
1493    /// Gets the type of the `Pair`.
1494    pub fn ty(&self) -> Type {
1495        self.ty.clone()
1496    }
1497
1498    /// Gets the left value of the `Pair`.
1499    pub fn left(&self) -> &Value {
1500        &self.values.0
1501    }
1502
1503    /// Gets the right value of the `Pair`.
1504    pub fn right(&self) -> &Value {
1505        &self.values.1
1506    }
1507}
1508
1509impl fmt::Display for Pair {
1510    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1511        write!(
1512            f,
1513            "({left}, {right})",
1514            left = self.values.0,
1515            right = self.values.1
1516        )
1517    }
1518}
1519
1520/// Represents an `Array` value.
1521///
1522/// Arrays are cheap to clone.
1523#[derive(Debug, Clone)]
1524pub struct Array {
1525    /// The type of the array.
1526    ty: Type,
1527    /// The array's elements.
1528    ///
1529    /// A value of `None` indicates an empty array.
1530    elements: Option<Arc<Vec<Value>>>,
1531}
1532
1533impl Array {
1534    /// Creates a new `Array` value for the given array type.
1535    ///
1536    /// Returns an error if an element did not coerce to the array's element
1537    /// type.
1538    ///
1539    /// # Panics
1540    ///
1541    /// Panics if the given type is not an array type.
1542    pub fn new<V>(ty: impl Into<Type>, elements: impl IntoIterator<Item = V>) -> Result<Self>
1543    where
1544        V: Into<Value>,
1545    {
1546        let ty = ty.into();
1547        if let Type::Compound(CompoundType::Array(ty), optional) = ty {
1548            let element_type = ty.element_type();
1549            let elements = elements
1550                .into_iter()
1551                .enumerate()
1552                .map(|(i, v)| {
1553                    let v = v.into();
1554                    v.coerce(element_type)
1555                        .with_context(|| format!("failed to coerce array element at index {i}"))
1556                })
1557                .collect::<Result<Vec<_>>>()?;
1558
1559            return Ok(Self::new_unchecked(
1560                Type::Compound(CompoundType::Array(ty), optional),
1561                elements,
1562            ));
1563        }
1564
1565        panic!("type `{ty}` is not an array type");
1566    }
1567
1568    /// Constructs a new array without checking the given elements conform to
1569    /// the given type.
1570    pub(crate) fn new_unchecked(ty: Type, elements: Vec<Value>) -> Self {
1571        assert!(ty.as_array().is_some());
1572        Self {
1573            ty,
1574            elements: if elements.is_empty() {
1575                None
1576            } else {
1577                Some(Arc::new(elements))
1578            },
1579        }
1580    }
1581
1582    /// Gets the type of the `Array` value.
1583    pub fn ty(&self) -> Type {
1584        self.ty.clone()
1585    }
1586
1587    /// Converts the array value to a slice of values.
1588    pub fn as_slice(&self) -> &[Value] {
1589        self.elements.as_ref().map(|v| v.as_slice()).unwrap_or(&[])
1590    }
1591
1592    /// Returns the number of elements in the array.
1593    pub fn len(&self) -> usize {
1594        self.elements.as_ref().map(|v| v.len()).unwrap_or(0)
1595    }
1596
1597    /// Returns `true` if the array has no elements.
1598    pub fn is_empty(&self) -> bool {
1599        self.len() == 0
1600    }
1601}
1602
1603impl fmt::Display for Array {
1604    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1605        write!(f, "[")?;
1606
1607        if let Some(elements) = &self.elements {
1608            for (i, element) in elements.iter().enumerate() {
1609                if i > 0 {
1610                    write!(f, ", ")?;
1611                }
1612
1613                write!(f, "{element}")?;
1614            }
1615        }
1616
1617        write!(f, "]")
1618    }
1619}
1620
1621/// Represents a `Map` value.
1622///
1623/// Maps are cheap to clone.
1624#[derive(Debug, Clone)]
1625pub struct Map {
1626    /// The type of the map value.
1627    ty: Type,
1628    /// The elements of the map value.
1629    ///
1630    /// A value of `None` indicates an empty map.
1631    elements: Option<Arc<IndexMap<Option<PrimitiveValue>, Value>>>,
1632}
1633
1634impl Map {
1635    /// Creates a new `Map` value.
1636    ///
1637    /// Returns an error if a key or value did not coerce to the map's key or
1638    /// value type, respectively.
1639    ///
1640    /// # Panics
1641    ///
1642    /// Panics if the given type is not a map type.
1643    pub fn new<K, V>(
1644        ty: impl Into<Type>,
1645        elements: impl IntoIterator<Item = (K, V)>,
1646    ) -> Result<Self>
1647    where
1648        K: Into<Value>,
1649        V: Into<Value>,
1650    {
1651        let ty = ty.into();
1652        if let Type::Compound(CompoundType::Map(ty), optional) = ty {
1653            let key_type = ty.key_type();
1654            let value_type = ty.value_type();
1655
1656            let elements = elements
1657                .into_iter()
1658                .enumerate()
1659                .map(|(i, (k, v))| {
1660                    let k = k.into();
1661                    let v = v.into();
1662                    Ok((
1663                        if k.is_none() {
1664                            None
1665                        } else {
1666                            match k.coerce(key_type).with_context(|| {
1667                                format!("failed to coerce map key for element at index {i}")
1668                            })? {
1669                                Value::None => None,
1670                                Value::Primitive(v) => Some(v),
1671                                _ => {
1672                                    bail!("not all key values are primitive")
1673                                }
1674                            }
1675                        },
1676                        v.coerce(value_type).with_context(|| {
1677                            format!("failed to coerce map value for element at index {i}")
1678                        })?,
1679                    ))
1680                })
1681                .collect::<Result<_>>()?;
1682
1683            return Ok(Self::new_unchecked(
1684                Type::Compound(CompoundType::Map(ty), optional),
1685                elements,
1686            ));
1687        }
1688
1689        panic!("type `{ty}` is not a map type");
1690    }
1691
1692    /// Constructs a new map without checking the given elements conform to the
1693    /// given type.
1694    pub(crate) fn new_unchecked(
1695        ty: Type,
1696        elements: IndexMap<Option<PrimitiveValue>, Value>,
1697    ) -> Self {
1698        assert!(ty.as_map().is_some());
1699        Self {
1700            ty,
1701            elements: if elements.is_empty() {
1702                None
1703            } else {
1704                Some(Arc::new(elements))
1705            },
1706        }
1707    }
1708
1709    /// Gets the type of the `Map` value.
1710    pub fn ty(&self) -> Type {
1711        self.ty.clone()
1712    }
1713
1714    /// Iterates the elements of the map.
1715    pub fn iter(&self) -> impl Iterator<Item = (&Option<PrimitiveValue>, &Value)> {
1716        self.elements
1717            .as_ref()
1718            .map(|m| Either::Left(m.iter()))
1719            .unwrap_or(Either::Right(std::iter::empty()))
1720    }
1721
1722    /// Iterates the keys of the map.
1723    pub fn keys(&self) -> impl Iterator<Item = &Option<PrimitiveValue>> {
1724        self.elements
1725            .as_ref()
1726            .map(|m| Either::Left(m.keys()))
1727            .unwrap_or(Either::Right(std::iter::empty()))
1728    }
1729
1730    /// Iterates the values of the map.
1731    pub fn values(&self) -> impl Iterator<Item = &Value> {
1732        self.elements
1733            .as_ref()
1734            .map(|m| Either::Left(m.values()))
1735            .unwrap_or(Either::Right(std::iter::empty()))
1736    }
1737
1738    /// Determines if the map contains the given key.
1739    pub fn contains_key(&self, key: &Option<PrimitiveValue>) -> bool {
1740        self.elements
1741            .as_ref()
1742            .map(|m| m.contains_key(key))
1743            .unwrap_or(false)
1744    }
1745
1746    /// Gets a value from the map by key.
1747    pub fn get(&self, key: &Option<PrimitiveValue>) -> Option<&Value> {
1748        self.elements.as_ref().and_then(|m| m.get(key))
1749    }
1750
1751    /// Returns the number of elements in the map.
1752    pub fn len(&self) -> usize {
1753        self.elements.as_ref().map(|m| m.len()).unwrap_or(0)
1754    }
1755
1756    /// Returns `true` if the map has no elements.
1757    pub fn is_empty(&self) -> bool {
1758        self.len() == 0
1759    }
1760}
1761
1762impl fmt::Display for Map {
1763    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1764        write!(f, "{{")?;
1765
1766        for (i, (k, v)) in self.iter().enumerate() {
1767            if i > 0 {
1768                write!(f, ", ")?;
1769            }
1770
1771            match k {
1772                Some(k) => write!(f, "{k}: {v}")?,
1773                None => write!(f, "None: {v}")?,
1774            }
1775        }
1776
1777        write!(f, "}}")
1778    }
1779}
1780
1781/// Represents an `Object` value.
1782///
1783/// Objects are cheap to clone.
1784#[derive(Debug, Clone)]
1785pub struct Object {
1786    /// The members of the object.
1787    ///
1788    /// A value of `None` indicates an empty object.
1789    pub(crate) members: Option<Arc<IndexMap<String, Value>>>,
1790}
1791
1792impl Object {
1793    /// Creates a new `Object` value.
1794    ///
1795    /// Keys **must** be known WDL identifiers checked by the caller.
1796    pub(crate) fn new(members: IndexMap<String, Value>) -> Self {
1797        Self {
1798            members: if members.is_empty() {
1799                None
1800            } else {
1801                Some(Arc::new(members))
1802            },
1803        }
1804    }
1805
1806    /// Returns an empty object.
1807    pub fn empty() -> Self {
1808        Self::new(IndexMap::default())
1809    }
1810
1811    /// Creates an object from an iterator of V1 AST metadata items.
1812    pub fn from_v1_metadata<N: TreeNode>(
1813        items: impl Iterator<Item = v1::MetadataObjectItem<N>>,
1814    ) -> Self {
1815        Object::new(
1816            items
1817                .map(|i| {
1818                    (
1819                        i.name().text().to_string(),
1820                        Value::from_v1_metadata(&i.value()),
1821                    )
1822                })
1823                .collect::<IndexMap<_, _>>(),
1824        )
1825    }
1826
1827    /// Gets the type of the `Object` value.
1828    pub fn ty(&self) -> Type {
1829        Type::Object
1830    }
1831
1832    /// Iterates the members of the object.
1833    pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
1834        self.members
1835            .as_ref()
1836            .map(|m| Either::Left(m.iter().map(|(k, v)| (k.as_str(), v))))
1837            .unwrap_or(Either::Right(std::iter::empty()))
1838    }
1839
1840    /// Iterates the keys of the object.
1841    pub fn keys(&self) -> impl Iterator<Item = &str> {
1842        self.members
1843            .as_ref()
1844            .map(|m| Either::Left(m.keys().map(|k| k.as_str())))
1845            .unwrap_or(Either::Right(std::iter::empty()))
1846    }
1847
1848    /// Iterates the values of the object.
1849    pub fn values(&self) -> impl Iterator<Item = &Value> {
1850        self.members
1851            .as_ref()
1852            .map(|m| Either::Left(m.values()))
1853            .unwrap_or(Either::Right(std::iter::empty()))
1854    }
1855
1856    /// Determines if the object contains the given key.
1857    pub fn contains_key(&self, key: &str) -> bool {
1858        self.members
1859            .as_ref()
1860            .map(|m| m.contains_key(key))
1861            .unwrap_or(false)
1862    }
1863
1864    /// Gets a value from the object by key.
1865    pub fn get(&self, key: &str) -> Option<&Value> {
1866        self.members.as_ref().and_then(|m| m.get(key))
1867    }
1868
1869    /// Returns the number of members in the object.
1870    pub fn len(&self) -> usize {
1871        self.members.as_ref().map(|m| m.len()).unwrap_or(0)
1872    }
1873
1874    /// Returns `true` if the object has no members.
1875    pub fn is_empty(&self) -> bool {
1876        self.len() == 0
1877    }
1878}
1879
1880impl fmt::Display for Object {
1881    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1882        write!(f, "object {{")?;
1883
1884        for (i, (k, v)) in self.iter().enumerate() {
1885            if i > 0 {
1886                write!(f, ", ")?;
1887            }
1888
1889            write!(f, "{k}: {v}")?;
1890        }
1891
1892        write!(f, "}}")
1893    }
1894}
1895
1896/// Represents a `Struct` value.
1897///
1898/// Structs are cheap to clone.
1899#[derive(Debug, Clone)]
1900pub struct Struct {
1901    /// The type of the struct value.
1902    ty: Type,
1903    /// The name of the struct.
1904    name: Arc<String>,
1905    /// The members of the struct value.
1906    pub(crate) members: Arc<IndexMap<String, Value>>,
1907}
1908
1909impl Struct {
1910    /// Creates a new struct value.
1911    ///
1912    /// Returns an error if the struct type does not contain a member of a given
1913    /// name or if a value does not coerce to the corresponding member's type.
1914    ///
1915    /// # Panics
1916    ///
1917    /// Panics if the given type is not a struct type.
1918    pub fn new<S, V>(ty: impl Into<Type>, members: impl IntoIterator<Item = (S, V)>) -> Result<Self>
1919    where
1920        S: Into<String>,
1921        V: Into<Value>,
1922    {
1923        let ty = ty.into();
1924        if let Type::Compound(CompoundType::Struct(ty), optional) = ty {
1925            let mut members = members
1926                .into_iter()
1927                .map(|(n, v)| {
1928                    let n = n.into();
1929                    let v = v.into();
1930                    let v = v
1931                        .coerce(ty.members().get(&n).ok_or_else(|| {
1932                            anyhow!("struct does not contain a member named `{n}`")
1933                        })?)
1934                        .with_context(|| format!("failed to coerce struct member `{n}`"))?;
1935                    Ok((n, v))
1936                })
1937                .collect::<Result<IndexMap<_, _>>>()?;
1938
1939            for (name, ty) in ty.members().iter() {
1940                // Check for optional members that should be set to `None`
1941                if ty.is_optional() {
1942                    if !members.contains_key(name) {
1943                        members.insert(name.clone(), Value::None);
1944                    }
1945                } else {
1946                    // Check for a missing required member
1947                    if !members.contains_key(name) {
1948                        bail!("missing a value for struct member `{name}`");
1949                    }
1950                }
1951            }
1952
1953            let name = ty.name().to_string();
1954            return Ok(Self {
1955                ty: Type::Compound(CompoundType::Struct(ty), optional),
1956                name: Arc::new(name),
1957                members: Arc::new(members),
1958            });
1959        }
1960
1961        panic!("type `{ty}` is not a struct type");
1962    }
1963
1964    /// Constructs a new struct without checking the given members conform to
1965    /// the given type.
1966    pub(crate) fn new_unchecked(
1967        ty: Type,
1968        name: Arc<String>,
1969        members: Arc<IndexMap<String, Value>>,
1970    ) -> Self {
1971        assert!(ty.as_struct().is_some());
1972        Self { ty, name, members }
1973    }
1974
1975    /// Gets the type of the `Struct` value.
1976    pub fn ty(&self) -> Type {
1977        self.ty.clone()
1978    }
1979
1980    /// Gets the name of the struct.
1981    pub fn name(&self) -> &Arc<String> {
1982        &self.name
1983    }
1984
1985    /// Iterates the members of the struct.
1986    pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
1987        self.members.iter().map(|(k, v)| (k.as_str(), v))
1988    }
1989
1990    /// Iterates the keys of the struct.
1991    pub fn keys(&self) -> impl Iterator<Item = &str> {
1992        self.members.keys().map(|k| k.as_str())
1993    }
1994
1995    /// Iterates the values of the struct.
1996    pub fn values(&self) -> impl Iterator<Item = &Value> {
1997        self.members.values()
1998    }
1999
2000    /// Determines if the struct contains the given member name.
2001    pub fn contains_key(&self, key: &str) -> bool {
2002        self.members.contains_key(key)
2003    }
2004
2005    /// Gets a value from the struct by member name.
2006    pub fn get(&self, key: &str) -> Option<&Value> {
2007        self.members.get(key)
2008    }
2009}
2010
2011impl fmt::Display for Struct {
2012    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2013        write!(f, "{name} {{", name = self.name)?;
2014
2015        for (i, (k, v)) in self.members.iter().enumerate() {
2016            if i > 0 {
2017                write!(f, ", ")?;
2018            }
2019
2020            write!(f, "{k}: {v}")?;
2021        }
2022
2023        write!(f, "}}")
2024    }
2025}
2026
2027/// Represents a compound value.
2028///
2029/// Compound values are cheap to clone.
2030#[derive(Debug, Clone)]
2031pub enum CompoundValue {
2032    /// The value is a `Pair` of values.
2033    Pair(Pair),
2034    /// The value is an `Array` of values.
2035    Array(Array),
2036    /// The value is a `Map` of values.
2037    Map(Map),
2038    /// The value is an `Object`.
2039    Object(Object),
2040    /// The value is a struct.
2041    Struct(Struct),
2042}
2043
2044impl CompoundValue {
2045    /// Gets the type of the compound value.
2046    pub fn ty(&self) -> Type {
2047        match self {
2048            CompoundValue::Pair(v) => v.ty(),
2049            CompoundValue::Array(v) => v.ty(),
2050            CompoundValue::Map(v) => v.ty(),
2051            CompoundValue::Object(v) => v.ty(),
2052            CompoundValue::Struct(v) => v.ty(),
2053        }
2054    }
2055
2056    /// Gets the value as a `Pair`.
2057    ///
2058    /// Returns `None` if the value is not a `Pair`.
2059    pub fn as_pair(&self) -> Option<&Pair> {
2060        match self {
2061            Self::Pair(v) => Some(v),
2062            _ => None,
2063        }
2064    }
2065
2066    /// Unwraps the value into a `Pair`.
2067    ///
2068    /// # Panics
2069    ///
2070    /// Panics if the value is not a `Pair`.
2071    pub fn unwrap_pair(self) -> Pair {
2072        match self {
2073            Self::Pair(v) => v,
2074            _ => panic!("value is not a pair"),
2075        }
2076    }
2077
2078    /// Gets the value as an `Array`.
2079    ///
2080    /// Returns `None` if the value is not an `Array`.
2081    pub fn as_array(&self) -> Option<&Array> {
2082        match self {
2083            Self::Array(v) => Some(v),
2084            _ => None,
2085        }
2086    }
2087
2088    /// Unwraps the value into an `Array`.
2089    ///
2090    /// # Panics
2091    ///
2092    /// Panics if the value is not an `Array`.
2093    pub fn unwrap_array(self) -> Array {
2094        match self {
2095            Self::Array(v) => v,
2096            _ => panic!("value is not an array"),
2097        }
2098    }
2099
2100    /// Gets the value as a `Map`.
2101    ///
2102    /// Returns `None` if the value is not a `Map`.
2103    pub fn as_map(&self) -> Option<&Map> {
2104        match self {
2105            Self::Map(v) => Some(v),
2106            _ => None,
2107        }
2108    }
2109
2110    /// Unwraps the value into a `Map`.
2111    ///
2112    /// # Panics
2113    ///
2114    /// Panics if the value is not a `Map`.
2115    pub fn unwrap_map(self) -> Map {
2116        match self {
2117            Self::Map(v) => v,
2118            _ => panic!("value is not a map"),
2119        }
2120    }
2121
2122    /// Gets the value as an `Object`.
2123    ///
2124    /// Returns `None` if the value is not an `Object`.
2125    pub fn as_object(&self) -> Option<&Object> {
2126        match self {
2127            Self::Object(v) => Some(v),
2128            _ => None,
2129        }
2130    }
2131
2132    /// Unwraps the value into an `Object`.
2133    ///
2134    /// # Panics
2135    ///
2136    /// Panics if the value is not an `Object`.
2137    pub fn unwrap_object(self) -> Object {
2138        match self {
2139            Self::Object(v) => v,
2140            _ => panic!("value is not an object"),
2141        }
2142    }
2143
2144    /// Gets the value as a `Struct`.
2145    ///
2146    /// Returns `None` if the value is not a `Struct`.
2147    pub fn as_struct(&self) -> Option<&Struct> {
2148        match self {
2149            Self::Struct(v) => Some(v),
2150            _ => None,
2151        }
2152    }
2153
2154    /// Unwraps the value into a `Struct`.
2155    ///
2156    /// # Panics
2157    ///
2158    /// Panics if the value is not a `Map`.
2159    pub fn unwrap_struct(self) -> Struct {
2160        match self {
2161            Self::Struct(v) => v,
2162            _ => panic!("value is not a struct"),
2163        }
2164    }
2165
2166    /// Compares two compound values for equality based on the WDL
2167    /// specification.
2168    ///
2169    /// Returns `None` if the two compound values cannot be compared for
2170    /// equality.
2171    pub fn equals(left: &Self, right: &Self) -> Option<bool> {
2172        // The values must have type equivalence to compare for compound values
2173        // Coercion doesn't take place for this check
2174        if left.ty() != right.ty() {
2175            return None;
2176        }
2177
2178        match (left, right) {
2179            (Self::Pair(left), Self::Pair(right)) => Some(
2180                Value::equals(left.left(), right.left())?
2181                    && Value::equals(left.right(), right.right())?,
2182            ),
2183            (CompoundValue::Array(left), CompoundValue::Array(right)) => Some(
2184                left.len() == right.len()
2185                    && left
2186                        .as_slice()
2187                        .iter()
2188                        .zip(right.as_slice())
2189                        .all(|(l, r)| Value::equals(l, r).unwrap_or(false)),
2190            ),
2191            (CompoundValue::Map(left), CompoundValue::Map(right)) => Some(
2192                left.len() == right.len()
2193                    // Maps are ordered, so compare via iteration
2194                    && left.iter().zip(right.iter()).all(|((lk, lv), (rk, rv))| {
2195                        match (lk, rk) {
2196                            (None, None) => {},
2197                            (Some(lk), Some(rk)) if lk == rk => {},
2198                            _ => return false
2199                        }
2200
2201                        Value::equals(lv, rv).unwrap_or(false)
2202                    }),
2203            ),
2204            (CompoundValue::Object(left), CompoundValue::Object(right)) => Some(
2205                left.len() == right.len()
2206                    && left.iter().all(|(k, left)| match right.get(k) {
2207                        Some(right) => Value::equals(left, right).unwrap_or(false),
2208                        None => false,
2209                    }),
2210            ),
2211            (
2212                CompoundValue::Struct(Struct { members: left, .. }),
2213                CompoundValue::Struct(Struct { members: right, .. }),
2214            ) => Some(
2215                left.len() == right.len()
2216                    && left.iter().all(|(k, left)| match right.get(k) {
2217                        Some(right) => Value::equals(left, right).unwrap_or(false),
2218                        None => false,
2219                    }),
2220            ),
2221            _ => None,
2222        }
2223    }
2224
2225    /// Visits each `File` or `Directory` value contained in this value.
2226    ///
2227    /// Note that paths may be specified as URLs.
2228    fn visit_paths(&self, cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>) -> Result<()> {
2229        match self {
2230            Self::Pair(pair) => {
2231                let ty = pair.ty.as_pair().expect("should be a pair type");
2232                pair.left().visit_paths(ty.left_type().is_optional(), cb)?;
2233                pair.right()
2234                    .visit_paths(ty.right_type().is_optional(), cb)?;
2235            }
2236            Self::Array(array) => {
2237                let ty = array.ty.as_array().expect("should be an array type");
2238                let optional = ty.element_type().is_optional();
2239                if let Some(elements) = &array.elements {
2240                    for v in elements.iter() {
2241                        v.visit_paths(optional, cb)?;
2242                    }
2243                }
2244            }
2245            Self::Map(map) => {
2246                let ty = map.ty.as_map().expect("should be a map type");
2247                let (key_optional, value_optional) =
2248                    (ty.key_type().is_optional(), ty.value_type().is_optional());
2249                if let Some(elements) = &map.elements {
2250                    for (k, v) in elements.iter() {
2251                        if let Some(k) = k {
2252                            k.visit_paths(key_optional, cb)?;
2253                        }
2254
2255                        v.visit_paths(value_optional, cb)?;
2256                    }
2257                }
2258            }
2259            Self::Object(object) => {
2260                if let Some(members) = &object.members {
2261                    for v in members.values() {
2262                        v.visit_paths(false, cb)?;
2263                    }
2264                }
2265            }
2266            Self::Struct(s) => {
2267                let ty = s.ty.as_struct().expect("should be a struct type");
2268                for (n, v) in s.members.iter() {
2269                    v.visit_paths(ty.members()[n].is_optional(), cb)?;
2270                }
2271            }
2272        }
2273
2274        Ok(())
2275    }
2276
2277    /// Mutably visits each `File` or `Directory` value contained in this value.
2278    ///
2279    /// If the provided callback returns `Ok(false)`, the `File` or `Directory`
2280    /// value will be replaced with `None`.
2281    ///
2282    /// Note that paths may be specified as URLs.
2283    fn visit_paths_mut(
2284        &mut self,
2285        cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
2286    ) -> Result<()> {
2287        match self {
2288            Self::Pair(pair) => {
2289                let ty = pair.ty.as_pair().expect("should be a pair type");
2290                let (left_optional, right_optional) =
2291                    (ty.left_type().is_optional(), ty.right_type().is_optional());
2292                let values = Arc::make_mut(&mut pair.values);
2293                values.0.visit_paths_mut(left_optional, cb)?;
2294                values.1.visit_paths_mut(right_optional, cb)?;
2295            }
2296            Self::Array(array) => {
2297                let ty = array.ty.as_array().expect("should be an array type");
2298                let optional = ty.element_type().is_optional();
2299                if let Some(elements) = &mut array.elements {
2300                    for v in Arc::make_mut(elements) {
2301                        v.visit_paths_mut(optional, cb)?;
2302                    }
2303                }
2304            }
2305            Self::Map(map) => {
2306                let ty = map.ty.as_map().expect("should be a map type");
2307                let (key_optional, value_optional) =
2308                    (ty.key_type().is_optional(), ty.value_type().is_optional());
2309                if let Some(elements) = &mut map.elements {
2310                    if elements
2311                        .iter()
2312                        .find_map(|(k, _)| {
2313                            k.as_ref().map(|v| {
2314                                matches!(v, PrimitiveValue::File(_) | PrimitiveValue::Directory(_))
2315                            })
2316                        })
2317                        .unwrap_or(false)
2318                    {
2319                        // The key type contains a path, we need to rebuild the map to alter the
2320                        // keys
2321                        let elements = Arc::make_mut(elements);
2322                        let new = elements
2323                            .drain(..)
2324                            .map(|(mut k, mut v)| {
2325                                if let Some(v) = &mut k {
2326                                    if !v.visit_paths_mut(key_optional, cb)? {
2327                                        k = None;
2328                                    }
2329                                }
2330
2331                                v.visit_paths_mut(value_optional, cb)?;
2332                                Ok((k, v))
2333                            })
2334                            .collect::<Result<Vec<_>>>()?;
2335                        elements.extend(new);
2336                    } else {
2337                        // Otherwise, we can just mutable the values in place
2338                        for v in Arc::make_mut(elements).values_mut() {
2339                            v.visit_paths_mut(value_optional, cb)?;
2340                        }
2341                    }
2342                }
2343            }
2344            Self::Object(object) => {
2345                if let Some(members) = &mut object.members {
2346                    for v in Arc::make_mut(members).values_mut() {
2347                        v.visit_paths_mut(false, cb)?;
2348                    }
2349                }
2350            }
2351            Self::Struct(s) => {
2352                let ty = s.ty.as_struct().expect("should be a struct type");
2353                for (n, v) in Arc::make_mut(&mut s.members).iter_mut() {
2354                    v.visit_paths_mut(ty.members()[n].is_optional(), cb)?;
2355                }
2356            }
2357        }
2358
2359        Ok(())
2360    }
2361
2362    /// Creates a clone of the value, but makes the type required.
2363    fn clone_as_required(&self) -> Self {
2364        match self {
2365            Self::Pair(v) => Self::Pair(Pair {
2366                ty: v.ty.require(),
2367                values: v.values.clone(),
2368            }),
2369            Self::Array(v) => Self::Array(Array {
2370                ty: v.ty.require(),
2371                elements: v.elements.clone(),
2372            }),
2373            Self::Map(v) => Self::Map(Map {
2374                ty: v.ty.require(),
2375                elements: v.elements.clone(),
2376            }),
2377            Self::Object(_) => self.clone(),
2378            Self::Struct(v) => Self::Struct(Struct {
2379                ty: v.ty.require(),
2380                name: v.name.clone(),
2381                members: v.members.clone(),
2382            }),
2383        }
2384    }
2385
2386    /// Creates a clone of the value, but makes the type optional.
2387    fn clone_as_optional(&self) -> Self {
2388        match self {
2389            Self::Pair(v) => Self::Pair(Pair {
2390                ty: v.ty.optional(),
2391                values: v.values.clone(),
2392            }),
2393            Self::Array(v) => Self::Array(Array {
2394                ty: v.ty.optional(),
2395                elements: v.elements.clone(),
2396            }),
2397            Self::Map(v) => Self::Map(Map {
2398                ty: v.ty.optional(),
2399                elements: v.elements.clone(),
2400            }),
2401            Self::Object(_) => self.clone(),
2402            Self::Struct(v) => Self::Struct(Struct {
2403                ty: v.ty.optional(),
2404                name: v.name.clone(),
2405                members: v.members.clone(),
2406            }),
2407        }
2408    }
2409}
2410
2411impl fmt::Display for CompoundValue {
2412    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2413        match self {
2414            Self::Pair(v) => v.fmt(f),
2415            Self::Array(v) => v.fmt(f),
2416            Self::Map(v) => v.fmt(f),
2417            Self::Object(v) => v.fmt(f),
2418            Self::Struct(v) => v.fmt(f),
2419        }
2420    }
2421}
2422
2423impl Coercible for CompoundValue {
2424    fn coerce(&self, target: &Type) -> Result<Self> {
2425        if target.is_union() || target.is_none() || self.ty().eq(target) {
2426            return Ok(self.clone());
2427        }
2428
2429        if let Type::Compound(target_ty, _) = target {
2430            match (self, target_ty) {
2431                // Array[X] -> Array[Y](+) where X -> Y
2432                (Self::Array(v), CompoundType::Array(target_ty)) => {
2433                    // Don't allow coercion when the source is empty but the target has the
2434                    // non-empty qualifier
2435                    if v.is_empty() && target_ty.is_non_empty() {
2436                        bail!("cannot coerce empty array value to non-empty array type `{target}`",);
2437                    }
2438
2439                    return Ok(Self::Array(Array::new(
2440                        target.clone(),
2441                        v.as_slice().iter().cloned(),
2442                    )?));
2443                }
2444                // Map[W, Y] -> Map[X, Z] where W -> X and Y -> Z
2445                (Self::Map(v), CompoundType::Map(_)) => {
2446                    return Ok(Self::Map(Map::new(
2447                        target.clone(),
2448                        v.iter().map(|(k, v)| {
2449                            (k.clone().map(Into::into).unwrap_or(Value::None), v.clone())
2450                        }),
2451                    )?));
2452                }
2453                // Pair[W, Y] -> Pair[X, Z] where W -> X and Y -> Z
2454                (Self::Pair(v), CompoundType::Pair(_)) => {
2455                    return Ok(Self::Pair(Pair::new(
2456                        target.clone(),
2457                        v.values.0.clone(),
2458                        v.values.1.clone(),
2459                    )?));
2460                }
2461                // Map[String, Y] -> Struct
2462                (Self::Map(v), CompoundType::Struct(target_ty)) => {
2463                    let len = v.len();
2464                    let expected_len = target_ty.members().len();
2465
2466                    if len != expected_len {
2467                        bail!(
2468                            "cannot coerce a map of {len} element{s1} to struct type `{target}` \
2469                             as the struct has {expected_len} member{s2}",
2470                            s1 = if len == 1 { "" } else { "s" },
2471                            s2 = if expected_len == 1 { "" } else { "s" }
2472                        );
2473                    }
2474
2475                    return Ok(Self::Struct(Struct {
2476                        ty: target.clone(),
2477                        name: target_ty.name().clone(),
2478                        members: Arc::new(
2479                            v.iter()
2480                                .map(|(k, v)| {
2481                                    let k: String = k
2482                                        .as_ref()
2483                                        .and_then(|k| k.as_string())
2484                                        .with_context(|| {
2485                                            format!(
2486                                                "cannot coerce a map with a non-string key type \
2487                                                 to struct type `{target}`"
2488                                            )
2489                                        })?
2490                                        .to_string();
2491                                    let ty = target_ty.members().get(&k).with_context(|| {
2492                                        format!(
2493                                            "cannot coerce a map with key `{k}` to struct type \
2494                                             `{target}` as the struct does not contain a member \
2495                                             with that name"
2496                                        )
2497                                    })?;
2498                                    let v = v.coerce(ty).with_context(|| {
2499                                        format!("failed to coerce value of map key `{k}")
2500                                    })?;
2501                                    Ok((k, v))
2502                                })
2503                                .collect::<Result<_>>()?,
2504                        ),
2505                    }));
2506                }
2507                // Struct -> Map[String, Y]
2508                // Object -> Map[String, Y]
2509                (Self::Struct(Struct { members, .. }), CompoundType::Map(map_ty)) => {
2510                    if map_ty.key_type().as_primitive() != Some(PrimitiveType::String) {
2511                        bail!(
2512                            "cannot coerce a struct or object to type `{target}` as it requires a \
2513                             `String` key type"
2514                        );
2515                    }
2516
2517                    let value_ty = map_ty.value_type();
2518                    return Ok(Self::Map(Map::new_unchecked(
2519                        target.clone(),
2520                        members
2521                            .iter()
2522                            .map(|(n, v)| {
2523                                let v = v
2524                                    .coerce(value_ty)
2525                                    .with_context(|| format!("failed to coerce member `{n}`"))?;
2526                                Ok((PrimitiveValue::new_string(n).into(), v))
2527                            })
2528                            .collect::<Result<_>>()?,
2529                    )));
2530                }
2531                (Self::Object(object), CompoundType::Map(map_ty)) => {
2532                    if map_ty.key_type().as_primitive() != Some(PrimitiveType::String) {
2533                        bail!(
2534                            "cannot coerce a struct or object to type `{target}` as it requires a \
2535                             `String` key type",
2536                        );
2537                    }
2538
2539                    let value_ty = map_ty.value_type();
2540                    return Ok(Self::Map(Map::new_unchecked(
2541                        target.clone(),
2542                        object
2543                            .iter()
2544                            .map(|(n, v)| {
2545                                let v = v
2546                                    .coerce(value_ty)
2547                                    .with_context(|| format!("failed to coerce member `{n}`"))?;
2548                                Ok((PrimitiveValue::new_string(n).into(), v))
2549                            })
2550                            .collect::<Result<_>>()?,
2551                    )));
2552                }
2553                // Object -> Struct
2554                (Self::Object(v), CompoundType::Struct(_)) => {
2555                    return Ok(Self::Struct(Struct::new(
2556                        target.clone(),
2557                        v.iter().map(|(k, v)| (k, v.clone())),
2558                    )?));
2559                }
2560                // Struct -> Struct
2561                (Self::Struct(v), CompoundType::Struct(struct_ty)) => {
2562                    let len = v.members.len();
2563                    let expected_len = struct_ty.members().len();
2564
2565                    if len != expected_len {
2566                        bail!(
2567                            "cannot coerce a struct of {len} members{s1} to struct type \
2568                             `{target}` as the target struct has {expected_len} member{s2}",
2569                            s1 = if len == 1 { "" } else { "s" },
2570                            s2 = if expected_len == 1 { "" } else { "s" }
2571                        );
2572                    }
2573
2574                    return Ok(Self::Struct(Struct {
2575                        ty: target.clone(),
2576                        name: struct_ty.name().clone(),
2577                        members: Arc::new(
2578                            v.members
2579                                .iter()
2580                                .map(|(k, v)| {
2581                                    let ty = struct_ty.members().get(k).ok_or_else(|| {
2582                                        anyhow!(
2583                                            "cannot coerce a struct with member `{k}` to struct \
2584                                             type `{target}` as the target struct does not \
2585                                             contain a member with that name",
2586                                        )
2587                                    })?;
2588                                    let v = v.coerce(ty).with_context(|| {
2589                                        format!("failed to coerce member `{k}`")
2590                                    })?;
2591                                    Ok((k.clone(), v))
2592                                })
2593                                .collect::<Result<_>>()?,
2594                        ),
2595                    }));
2596                }
2597                _ => {}
2598            }
2599        }
2600
2601        if let Type::Object = target {
2602            match self {
2603                // Map[String, Y] -> Object
2604                Self::Map(v) => {
2605                    return Ok(Self::Object(Object::new(
2606                        v.iter()
2607                            .map(|(k, v)| {
2608                                let k = k
2609                                    .as_ref()
2610                                    .and_then(|k| k.as_string())
2611                                    .context(
2612                                        "cannot coerce a map with a non-string key type to type \
2613                                         `Object`",
2614                                    )?
2615                                    .to_string();
2616                                Ok((k, v.clone()))
2617                            })
2618                            .collect::<Result<IndexMap<_, _>>>()?,
2619                    )));
2620                }
2621                // Struct -> Object
2622                Self::Struct(v) => {
2623                    return Ok(Self::Object(Object {
2624                        members: Some(v.members.clone()),
2625                    }));
2626                }
2627                _ => {}
2628            };
2629        }
2630
2631        bail!(
2632            "cannot coerce a value of type `{ty}` to type `{target}`",
2633            ty = self.ty()
2634        );
2635    }
2636}
2637
2638impl From<Pair> for CompoundValue {
2639    fn from(value: Pair) -> Self {
2640        Self::Pair(value)
2641    }
2642}
2643
2644impl From<Array> for CompoundValue {
2645    fn from(value: Array) -> Self {
2646        Self::Array(value)
2647    }
2648}
2649
2650impl From<Map> for CompoundValue {
2651    fn from(value: Map) -> Self {
2652        Self::Map(value)
2653    }
2654}
2655
2656impl From<Object> for CompoundValue {
2657    fn from(value: Object) -> Self {
2658        Self::Object(value)
2659    }
2660}
2661
2662impl From<Struct> for CompoundValue {
2663    fn from(value: Struct) -> Self {
2664        Self::Struct(value)
2665    }
2666}
2667
2668impl serde::Serialize for CompoundValue {
2669    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2670    where
2671        S: serde::Serializer,
2672    {
2673        use serde::ser::Error;
2674
2675        match self {
2676            Self::Pair(_) => Err(S::Error::custom("a pair cannot be serialized")),
2677            Self::Array(v) => {
2678                let mut s = serializer.serialize_seq(Some(v.len()))?;
2679                for v in v.as_slice() {
2680                    s.serialize_element(v)?;
2681                }
2682
2683                s.end()
2684            }
2685            Self::Map(v) => {
2686                if !v
2687                    .ty()
2688                    .as_map()
2689                    .expect("type should be a map")
2690                    .key_type()
2691                    .is_coercible_to(&PrimitiveType::String.into())
2692                {
2693                    return Err(S::Error::custom(
2694                        "only maps with `String` key types may be serialized",
2695                    ));
2696                }
2697
2698                let mut s = serializer.serialize_map(Some(v.len()))?;
2699                for (k, v) in v.iter() {
2700                    s.serialize_entry(k, v)?;
2701                }
2702
2703                s.end()
2704            }
2705            Self::Object(object) => {
2706                let mut s = serializer.serialize_map(Some(object.len()))?;
2707                for (k, v) in object.iter() {
2708                    s.serialize_entry(k, v)?;
2709                }
2710
2711                s.end()
2712            }
2713            Self::Struct(Struct { members, .. }) => {
2714                let mut s = serializer.serialize_map(Some(members.len()))?;
2715                for (k, v) in members.iter() {
2716                    s.serialize_entry(k, v)?;
2717                }
2718
2719                s.end()
2720            }
2721        }
2722    }
2723}
2724
2725/// Immutable data for task values.
2726#[derive(Debug)]
2727struct TaskData {
2728    /// The name of the task.
2729    name: Arc<String>,
2730    /// The id of the task.
2731    id: Arc<String>,
2732    /// The container of the task.
2733    container: Option<Arc<String>>,
2734    /// The allocated number of cpus for the task.
2735    cpu: f64,
2736    /// The allocated memory (in bytes) for the task.
2737    memory: i64,
2738    /// The GPU allocations for the task.
2739    ///
2740    /// An array with one specification per allocated GPU; the specification is
2741    /// execution engine-specific.
2742    gpu: Array,
2743    /// The FPGA allocations for the task.
2744    ///
2745    /// An array with one specification per allocated FPGA; the specification is
2746    /// execution engine-specific.
2747    fpga: Array,
2748    /// The disk allocations for the task.
2749    ///
2750    /// A map with one entry for each disk mount point.
2751    ///
2752    /// The key is the mount point and the value is the initial amount of disk
2753    /// space allocated, in bytes.
2754    disks: Map,
2755    /// The time by which the task must be completed, as a Unix time stamp.
2756    ///
2757    /// A value of `None` indicates there is no deadline.
2758    end_time: Option<i64>,
2759    /// The task's `meta` section as an object.
2760    meta: Object,
2761    /// The tasks's `parameter_meta` section as an object.
2762    parameter_meta: Object,
2763    /// The task's extension metadata.
2764    ext: Object,
2765}
2766
2767/// Represents a value for `task` variables in WDL 1.2.
2768///
2769/// Task values are cheap to clone.
2770#[derive(Debug, Clone)]
2771pub struct TaskValue {
2772    /// The immutable data for task values.
2773    data: Arc<TaskData>,
2774    /// The current task attempt count.
2775    ///
2776    /// The value must be 0 the first time the task is executed and incremented
2777    /// by 1 each time the task is retried (if any).
2778    attempt: i64,
2779    /// The task's return code.
2780    ///
2781    /// Initially set to `None`, but set after task execution completes.
2782    return_code: Option<i64>,
2783}
2784
2785impl TaskValue {
2786    /// Constructs a new task value with the given name and identifier.
2787    pub(crate) fn new_v1<N: TreeNode>(
2788        name: impl Into<String>,
2789        id: impl Into<String>,
2790        definition: &v1::TaskDefinition<N>,
2791        constraints: TaskExecutionConstraints,
2792        attempt: i64,
2793    ) -> Self {
2794        Self {
2795            data: Arc::new(TaskData {
2796                name: Arc::new(name.into()),
2797                id: Arc::new(id.into()),
2798                container: constraints.container.map(Into::into),
2799                cpu: constraints.cpu,
2800                memory: constraints.memory,
2801                gpu: Array::new_unchecked(
2802                    ANALYSIS_STDLIB.array_string_type().clone(),
2803                    constraints
2804                        .gpu
2805                        .into_iter()
2806                        .map(|v| PrimitiveValue::new_string(v).into())
2807                        .collect(),
2808                ),
2809                fpga: Array::new_unchecked(
2810                    ANALYSIS_STDLIB.array_string_type().clone(),
2811                    constraints
2812                        .fpga
2813                        .into_iter()
2814                        .map(|v| PrimitiveValue::new_string(v).into())
2815                        .collect(),
2816                ),
2817                disks: Map::new_unchecked(
2818                    ANALYSIS_STDLIB.map_string_int_type().clone(),
2819                    constraints
2820                        .disks
2821                        .into_iter()
2822                        .map(|(k, v)| (Some(PrimitiveValue::new_string(k)), v.into()))
2823                        .collect(),
2824                ),
2825                end_time: None,
2826                meta: definition
2827                    .metadata()
2828                    .map(|s| Object::from_v1_metadata(s.items()))
2829                    .unwrap_or_else(Object::empty),
2830                parameter_meta: definition
2831                    .parameter_metadata()
2832                    .map(|s| Object::from_v1_metadata(s.items()))
2833                    .unwrap_or_else(Object::empty),
2834                ext: Object::empty(),
2835            }),
2836            attempt,
2837            return_code: None,
2838        }
2839    }
2840
2841    /// Gets the task name.
2842    pub fn name(&self) -> &Arc<String> {
2843        &self.data.name
2844    }
2845
2846    /// Gets the unique ID of the task.
2847    pub fn id(&self) -> &Arc<String> {
2848        &self.data.id
2849    }
2850
2851    /// Gets the container in which the task is executing.
2852    pub fn container(&self) -> Option<&Arc<String>> {
2853        self.data.container.as_ref()
2854    }
2855
2856    /// Gets the allocated number of cpus for the task.
2857    pub fn cpu(&self) -> f64 {
2858        self.data.cpu
2859    }
2860
2861    /// Gets the allocated memory (in bytes) for the task.
2862    pub fn memory(&self) -> i64 {
2863        self.data.memory
2864    }
2865
2866    /// Gets the GPU allocations for the task.
2867    ///
2868    /// An array with one specification per allocated GPU; the specification is
2869    /// execution engine-specific.
2870    pub fn gpu(&self) -> &Array {
2871        &self.data.gpu
2872    }
2873
2874    /// Gets the FPGA allocations for the task.
2875    ///
2876    /// An array with one specification per allocated FPGA; the specification is
2877    /// execution engine-specific.
2878    pub fn fpga(&self) -> &Array {
2879        &self.data.fpga
2880    }
2881
2882    /// Gets the disk allocations for the task.
2883    ///
2884    /// A map with one entry for each disk mount point.
2885    ///
2886    /// The key is the mount point and the value is the initial amount of disk
2887    /// space allocated, in bytes.
2888    pub fn disks(&self) -> &Map {
2889        &self.data.disks
2890    }
2891
2892    /// Gets current task attempt count.
2893    ///
2894    /// The value must be 0 the first time the task is executed and incremented
2895    /// by 1 each time the task is retried (if any).
2896    pub fn attempt(&self) -> i64 {
2897        self.attempt
2898    }
2899
2900    /// Gets the time by which the task must be completed, as a Unix time stamp.
2901    ///
2902    /// A value of `None` indicates there is no deadline.
2903    pub fn end_time(&self) -> Option<i64> {
2904        self.data.end_time
2905    }
2906
2907    /// Gets the task's return code.
2908    ///
2909    /// Initially set to `None`, but set after task execution completes.
2910    pub fn return_code(&self) -> Option<i64> {
2911        self.return_code
2912    }
2913
2914    /// Gets the task's `meta` section as an object.
2915    pub fn meta(&self) -> &Object {
2916        &self.data.meta
2917    }
2918
2919    /// Gets the tasks's `parameter_meta` section as an object.
2920    pub fn parameter_meta(&self) -> &Object {
2921        &self.data.parameter_meta
2922    }
2923
2924    /// Gets the task's extension metadata.
2925    pub fn ext(&self) -> &Object {
2926        &self.data.ext
2927    }
2928
2929    /// Sets the return code after the task execution has completed.
2930    pub(crate) fn set_return_code(&mut self, code: i32) {
2931        self.return_code = Some(code as i64);
2932    }
2933
2934    /// Sets the attempt number for the task.
2935    pub(crate) fn set_attempt(&mut self, attempt: i64) {
2936        self.attempt = attempt;
2937    }
2938
2939    /// Accesses a field of the task value by name.
2940    ///
2941    /// Returns `None` if the name is not a known field name.
2942    pub fn field(&self, name: &str) -> Option<Value> {
2943        match name {
2944            n if n == TASK_FIELD_NAME => {
2945                Some(PrimitiveValue::String(self.data.name.clone()).into())
2946            }
2947            n if n == TASK_FIELD_ID => Some(PrimitiveValue::String(self.data.id.clone()).into()),
2948            n if n == TASK_FIELD_CONTAINER => Some(
2949                self.data
2950                    .container
2951                    .clone()
2952                    .map(|c| PrimitiveValue::String(c).into())
2953                    .unwrap_or(Value::None),
2954            ),
2955            n if n == TASK_FIELD_CPU => Some(self.data.cpu.into()),
2956            n if n == TASK_FIELD_MEMORY => Some(self.data.memory.into()),
2957            n if n == TASK_FIELD_GPU => Some(self.data.gpu.clone().into()),
2958            n if n == TASK_FIELD_FPGA => Some(self.data.fpga.clone().into()),
2959            n if n == TASK_FIELD_DISKS => Some(self.data.disks.clone().into()),
2960            n if n == TASK_FIELD_ATTEMPT => Some(self.attempt.into()),
2961            n if n == TASK_FIELD_END_TIME => {
2962                Some(self.data.end_time.map(Into::into).unwrap_or(Value::None))
2963            }
2964            n if n == TASK_FIELD_RETURN_CODE => {
2965                Some(self.return_code.map(Into::into).unwrap_or(Value::None))
2966            }
2967            n if n == TASK_FIELD_META => Some(self.data.meta.clone().into()),
2968            n if n == TASK_FIELD_PARAMETER_META => Some(self.data.parameter_meta.clone().into()),
2969            n if n == TASK_FIELD_EXT => Some(self.data.ext.clone().into()),
2970            _ => None,
2971        }
2972    }
2973}
2974
2975/// Represents a hints value from a WDL 1.2 hints section.
2976///
2977/// Hints values are cheap to clone.
2978#[derive(Debug, Clone)]
2979pub struct HintsValue(Object);
2980
2981impl HintsValue {
2982    /// Converts the hints value to an object.
2983    pub fn as_object(&self) -> &Object {
2984        &self.0
2985    }
2986}
2987
2988impl fmt::Display for HintsValue {
2989    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2990        write!(f, "hints {{")?;
2991
2992        for (i, (k, v)) in self.0.iter().enumerate() {
2993            if i > 0 {
2994                write!(f, ", ")?;
2995            }
2996
2997            write!(f, "{k}: {v}")?;
2998        }
2999
3000        write!(f, "}}")
3001    }
3002}
3003
3004impl From<Object> for HintsValue {
3005    fn from(value: Object) -> Self {
3006        Self(value)
3007    }
3008}
3009
3010/// Represents an input value from a WDL 1.2 hints section.
3011///
3012/// Input values are cheap to clone.
3013#[derive(Debug, Clone)]
3014pub struct InputValue(Object);
3015
3016impl InputValue {
3017    /// Converts the input value to an object.
3018    pub fn as_object(&self) -> &Object {
3019        &self.0
3020    }
3021}
3022
3023impl fmt::Display for InputValue {
3024    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3025        write!(f, "input {{")?;
3026
3027        for (i, (k, v)) in self.0.iter().enumerate() {
3028            if i > 0 {
3029                write!(f, ", ")?;
3030            }
3031
3032            write!(f, "{k}: {v}")?;
3033        }
3034
3035        write!(f, "}}")
3036    }
3037}
3038
3039impl From<Object> for InputValue {
3040    fn from(value: Object) -> Self {
3041        Self(value)
3042    }
3043}
3044
3045/// Represents an output value from a WDL 1.2 hints section.
3046///
3047/// Output values are cheap to clone.
3048#[derive(Debug, Clone)]
3049pub struct OutputValue(Object);
3050
3051impl OutputValue {
3052    /// Converts the output value to an object.
3053    pub fn as_object(&self) -> &Object {
3054        &self.0
3055    }
3056}
3057
3058impl fmt::Display for OutputValue {
3059    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3060        write!(f, "output {{")?;
3061
3062        for (i, (k, v)) in self.0.iter().enumerate() {
3063            if i > 0 {
3064                write!(f, ", ")?;
3065            }
3066
3067            write!(f, "{k}: {v}")?;
3068        }
3069
3070        write!(f, "}}")
3071    }
3072}
3073
3074impl From<Object> for OutputValue {
3075    fn from(value: Object) -> Self {
3076        Self(value)
3077    }
3078}
3079
3080/// Represents the outputs of a call.
3081///
3082/// Call values are cheap to clone.
3083#[derive(Debug, Clone)]
3084pub struct CallValue {
3085    /// The type of the call.
3086    ty: CallType,
3087    /// The outputs of the call.
3088    outputs: Arc<Outputs>,
3089}
3090
3091impl CallValue {
3092    /// Constructs a new call value without checking the outputs conform to the
3093    /// call type.
3094    pub(crate) fn new_unchecked(ty: CallType, outputs: Arc<Outputs>) -> Self {
3095        Self { ty, outputs }
3096    }
3097
3098    /// Gets the type of the call.
3099    pub fn ty(&self) -> &CallType {
3100        &self.ty
3101    }
3102
3103    /// Gets the outputs of the call.
3104    pub fn outputs(&self) -> &Outputs {
3105        self.outputs.as_ref()
3106    }
3107}
3108
3109impl fmt::Display for CallValue {
3110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3111        write!(f, "call output {{")?;
3112
3113        for (i, (k, v)) in self.outputs.iter().enumerate() {
3114            if i > 0 {
3115                write!(f, ", ")?;
3116            }
3117
3118            write!(f, "{k}: {v}")?;
3119        }
3120
3121        write!(f, "}}")
3122    }
3123}
3124
3125#[cfg(test)]
3126mod test {
3127    use approx::assert_relative_eq;
3128    use pretty_assertions::assert_eq;
3129    use wdl_analysis::types::ArrayType;
3130    use wdl_analysis::types::MapType;
3131    use wdl_analysis::types::PairType;
3132    use wdl_analysis::types::StructType;
3133
3134    use super::*;
3135
3136    #[test]
3137    fn boolean_coercion() {
3138        // Boolean -> Boolean
3139        assert_eq!(
3140            Value::from(false)
3141                .coerce(&PrimitiveType::Boolean.into())
3142                .expect("should coerce")
3143                .unwrap_boolean(),
3144            Value::from(false).unwrap_boolean()
3145        );
3146        // Boolean -> String (invalid)
3147        assert_eq!(
3148            format!(
3149                "{e:?}",
3150                e = Value::from(true)
3151                    .coerce(&PrimitiveType::String.into())
3152                    .unwrap_err()
3153            ),
3154            "cannot coerce type `Boolean` to type `String`"
3155        );
3156    }
3157
3158    #[test]
3159    fn boolean_display() {
3160        assert_eq!(Value::from(false).to_string(), "false");
3161        assert_eq!(Value::from(true).to_string(), "true");
3162    }
3163
3164    #[test]
3165    fn integer_coercion() {
3166        // Int -> Int
3167        assert_eq!(
3168            Value::from(12345)
3169                .coerce(&PrimitiveType::Integer.into())
3170                .expect("should coerce")
3171                .unwrap_integer(),
3172            Value::from(12345).unwrap_integer()
3173        );
3174        // Int -> Float
3175        assert_relative_eq!(
3176            Value::from(12345)
3177                .coerce(&PrimitiveType::Float.into())
3178                .expect("should coerce")
3179                .unwrap_float(),
3180            Value::from(12345.0).unwrap_float()
3181        );
3182        // Int -> Boolean (invalid)
3183        assert_eq!(
3184            format!(
3185                "{e:?}",
3186                e = Value::from(12345)
3187                    .coerce(&PrimitiveType::Boolean.into())
3188                    .unwrap_err()
3189            ),
3190            "cannot coerce type `Int` to type `Boolean`"
3191        );
3192    }
3193
3194    #[test]
3195    fn integer_display() {
3196        assert_eq!(Value::from(12345).to_string(), "12345");
3197        assert_eq!(Value::from(-12345).to_string(), "-12345");
3198    }
3199
3200    #[test]
3201    fn float_coercion() {
3202        // Float -> Float
3203        assert_relative_eq!(
3204            Value::from(12345.0)
3205                .coerce(&PrimitiveType::Float.into())
3206                .expect("should coerce")
3207                .unwrap_float(),
3208            Value::from(12345.0).unwrap_float()
3209        );
3210        // Float -> Int (invalid)
3211        assert_eq!(
3212            format!(
3213                "{e:?}",
3214                e = Value::from(12345.0)
3215                    .coerce(&PrimitiveType::Integer.into())
3216                    .unwrap_err()
3217            ),
3218            "cannot coerce type `Float` to type `Int`"
3219        );
3220    }
3221
3222    #[test]
3223    fn float_display() {
3224        assert_eq!(Value::from(12345.12345).to_string(), "12345.123450");
3225        assert_eq!(Value::from(-12345.12345).to_string(), "-12345.123450");
3226    }
3227
3228    #[test]
3229    fn string_coercion() {
3230        let value = PrimitiveValue::new_string("foo");
3231        // String -> String
3232        assert_eq!(
3233            value
3234                .coerce(&PrimitiveType::String.into())
3235                .expect("should coerce"),
3236            value
3237        );
3238        // String -> File
3239        assert_eq!(
3240            value
3241                .coerce(&PrimitiveType::File.into())
3242                .expect("should coerce"),
3243            PrimitiveValue::File(value.as_string().expect("should be string").clone())
3244        );
3245        // String -> Directory
3246        assert_eq!(
3247            value
3248                .coerce(&PrimitiveType::Directory.into())
3249                .expect("should coerce"),
3250            PrimitiveValue::Directory(value.as_string().expect("should be string").clone())
3251        );
3252        // String -> Boolean (invalid)
3253        assert_eq!(
3254            format!(
3255                "{e:?}",
3256                e = value.coerce(&PrimitiveType::Boolean.into()).unwrap_err()
3257            ),
3258            "cannot coerce type `String` to type `Boolean`"
3259        );
3260    }
3261
3262    #[test]
3263    fn string_display() {
3264        let value = PrimitiveValue::new_string("hello world!");
3265        assert_eq!(value.to_string(), "\"hello world!\"");
3266    }
3267
3268    #[test]
3269    fn file_coercion() {
3270        let value = PrimitiveValue::new_file("foo");
3271
3272        // File -> File
3273        assert_eq!(
3274            value
3275                .coerce(&PrimitiveType::File.into())
3276                .expect("should coerce"),
3277            value
3278        );
3279        // File -> String
3280        assert_eq!(
3281            value
3282                .coerce(&PrimitiveType::String.into())
3283                .expect("should coerce"),
3284            PrimitiveValue::String(value.as_file().expect("should be file").clone())
3285        );
3286        // File -> Directory (invalid)
3287        assert_eq!(
3288            format!(
3289                "{e:?}",
3290                e = value.coerce(&PrimitiveType::Directory.into()).unwrap_err()
3291            ),
3292            "cannot coerce type `File` to type `Directory`"
3293        );
3294    }
3295
3296    #[test]
3297    fn file_display() {
3298        let value = PrimitiveValue::new_file("/foo/bar/baz.txt");
3299        assert_eq!(value.to_string(), "\"/foo/bar/baz.txt\"");
3300    }
3301
3302    #[test]
3303    fn directory_coercion() {
3304        let value = PrimitiveValue::new_directory("foo");
3305
3306        // Directory -> Directory
3307        assert_eq!(
3308            value
3309                .coerce(&PrimitiveType::Directory.into())
3310                .expect("should coerce"),
3311            value
3312        );
3313        // Directory -> String
3314        assert_eq!(
3315            value
3316                .coerce(&PrimitiveType::String.into())
3317                .expect("should coerce"),
3318            PrimitiveValue::String(value.as_directory().expect("should be directory").clone())
3319        );
3320        // Directory -> File (invalid)
3321        assert_eq!(
3322            format!(
3323                "{e:?}",
3324                e = value.coerce(&PrimitiveType::File.into()).unwrap_err()
3325            ),
3326            "cannot coerce type `Directory` to type `File`"
3327        );
3328    }
3329
3330    #[test]
3331    fn directory_display() {
3332        let value = PrimitiveValue::new_directory("/foo/bar/baz");
3333        assert_eq!(value.to_string(), "\"/foo/bar/baz\"");
3334    }
3335
3336    #[test]
3337    fn none_coercion() {
3338        // None -> String?
3339        assert!(
3340            Value::None
3341                .coerce(&Type::from(PrimitiveType::String).optional())
3342                .expect("should coerce")
3343                .is_none(),
3344        );
3345
3346        // None -> String (invalid)
3347        assert_eq!(
3348            format!(
3349                "{e:?}",
3350                e = Value::None
3351                    .coerce(&PrimitiveType::String.into())
3352                    .unwrap_err()
3353            ),
3354            "cannot coerce `None` to non-optional type `String`"
3355        );
3356    }
3357
3358    #[test]
3359    fn none_display() {
3360        assert_eq!(Value::None.to_string(), "None");
3361    }
3362
3363    #[test]
3364    fn array_coercion() {
3365        let src_ty: Type = ArrayType::new(PrimitiveType::Integer).into();
3366        let target_ty: Type = ArrayType::new(PrimitiveType::Float).into();
3367
3368        // Array[Int] -> Array[Float]
3369        let src: CompoundValue = Array::new(src_ty, [1, 2, 3])
3370            .expect("should create array value")
3371            .into();
3372        let target = src.coerce(&target_ty).expect("should coerce");
3373        assert_eq!(
3374            target.unwrap_array().to_string(),
3375            "[1.000000, 2.000000, 3.000000]"
3376        );
3377
3378        // Array[Int] -> Array[String] (invalid)
3379        let target_ty: Type = ArrayType::new(PrimitiveType::String).into();
3380        assert_eq!(
3381            format!("{e:?}", e = src.coerce(&target_ty).unwrap_err()),
3382            r#"failed to coerce array element at index 0
3383
3384Caused by:
3385    cannot coerce type `Int` to type `String`"#
3386        );
3387    }
3388
3389    #[test]
3390    fn non_empty_array_coercion() {
3391        let ty: Type = ArrayType::new(PrimitiveType::String).into();
3392        let target_ty: Type = ArrayType::non_empty(PrimitiveType::String).into();
3393
3394        // Array[String] (non-empty) -> Array[String]+
3395        let string = PrimitiveValue::new_string("foo");
3396        let value: Value = Array::new(ty.clone(), [string])
3397            .expect("should create array")
3398            .into();
3399        assert!(value.coerce(&target_ty).is_ok(), "should coerce");
3400
3401        // Array[String] (empty) -> Array[String]+ (invalid)
3402        let value: Value = Array::new::<Value>(ty, [])
3403            .expect("should create array")
3404            .into();
3405        assert_eq!(
3406            format!("{e:?}", e = value.coerce(&target_ty).unwrap_err()),
3407            "cannot coerce empty array value to non-empty array type `Array[String]+`"
3408        );
3409    }
3410
3411    #[test]
3412    fn array_display() {
3413        let ty: Type = ArrayType::new(PrimitiveType::Integer).into();
3414        let value: Value = Array::new(ty, [1, 2, 3])
3415            .expect("should create array")
3416            .into();
3417
3418        assert_eq!(value.to_string(), "[1, 2, 3]");
3419    }
3420
3421    #[test]
3422    fn map_coerce() {
3423        let key1 = PrimitiveValue::new_file("foo");
3424        let value1 = PrimitiveValue::new_string("bar");
3425        let key2 = PrimitiveValue::new_file("baz");
3426        let value2 = PrimitiveValue::new_string("qux");
3427
3428        let ty = MapType::new(PrimitiveType::File, PrimitiveType::String);
3429        let value: Value = Map::new(ty, [(key1, value1), (key2, value2)])
3430            .expect("should create map value")
3431            .into();
3432
3433        // Map[File, String] -> Map[String, File]
3434        let ty = MapType::new(PrimitiveType::String, PrimitiveType::File).into();
3435        let value = value.coerce(&ty).expect("value should coerce");
3436        assert_eq!(value.to_string(), r#"{"foo": "bar", "baz": "qux"}"#);
3437
3438        // Map[String, File] -> Map[Int, File] (invalid)
3439        let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::File).into();
3440        assert_eq!(
3441            format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3442            r#"failed to coerce map key for element at index 0
3443
3444Caused by:
3445    cannot coerce type `String` to type `Int`"#
3446        );
3447
3448        // Map[String, File] -> Map[String, Int] (invalid)
3449        let ty = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
3450        assert_eq!(
3451            format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3452            r#"failed to coerce map value for element at index 0
3453
3454Caused by:
3455    cannot coerce type `File` to type `Int`"#
3456        );
3457
3458        // Map[String, File] -> Struct
3459        let ty = StructType::new(
3460            "Foo",
3461            [("foo", PrimitiveType::File), ("baz", PrimitiveType::File)],
3462        )
3463        .into();
3464        let struct_value = value.coerce(&ty).expect("value should coerce");
3465        assert_eq!(struct_value.to_string(), r#"Foo {foo: "bar", baz: "qux"}"#);
3466
3467        // Map[String, File] -> Struct (invalid)
3468        let ty = StructType::new(
3469            "Foo",
3470            [
3471                ("foo", PrimitiveType::File),
3472                ("baz", PrimitiveType::File),
3473                ("qux", PrimitiveType::File),
3474            ],
3475        )
3476        .into();
3477        assert_eq!(
3478            format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3479            "cannot coerce a map of 2 elements to struct type `Foo` as the struct has 3 members"
3480        );
3481
3482        // Map[String, File] -> Object
3483        let object_value = value.coerce(&Type::Object).expect("value should coerce");
3484        assert_eq!(
3485            object_value.to_string(),
3486            r#"object {foo: "bar", baz: "qux"}"#
3487        );
3488    }
3489
3490    #[test]
3491    fn map_display() {
3492        let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::Boolean);
3493        let value: Value = Map::new(ty, [(1, true), (2, false)])
3494            .expect("should create map value")
3495            .into();
3496        assert_eq!(value.to_string(), "{1: true, 2: false}");
3497    }
3498
3499    #[test]
3500    fn pair_coercion() {
3501        let left = PrimitiveValue::new_file("foo");
3502        let right = PrimitiveValue::new_string("bar");
3503
3504        let ty = PairType::new(PrimitiveType::File, PrimitiveType::String);
3505        let value: Value = Pair::new(ty, left, right)
3506            .expect("should create map value")
3507            .into();
3508
3509        // Pair[File, String] -> Pair[String, File]
3510        let ty = PairType::new(PrimitiveType::String, PrimitiveType::File).into();
3511        let value = value.coerce(&ty).expect("value should coerce");
3512        assert_eq!(value.to_string(), r#"("foo", "bar")"#);
3513
3514        // Pair[String, File] -> Pair[Int, Int]
3515        let ty = PairType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
3516        assert_eq!(
3517            format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3518            r#"failed to coerce pair's left value
3519
3520Caused by:
3521    cannot coerce type `String` to type `Int`"#
3522        );
3523    }
3524
3525    #[test]
3526    fn pair_display() {
3527        let ty = PairType::new(PrimitiveType::Integer, PrimitiveType::Boolean);
3528        let value: Value = Pair::new(ty, 12345, false)
3529            .expect("should create pair value")
3530            .into();
3531        assert_eq!(value.to_string(), "(12345, false)");
3532    }
3533
3534    #[test]
3535    fn struct_coercion() {
3536        let ty = StructType::new(
3537            "Foo",
3538            [
3539                ("foo", PrimitiveType::Float),
3540                ("bar", PrimitiveType::Float),
3541                ("baz", PrimitiveType::Float),
3542            ],
3543        );
3544        let value: Value = Struct::new(ty, [("foo", 1.0), ("bar", 2.0), ("baz", 3.0)])
3545            .expect("should create map value")
3546            .into();
3547
3548        // Struct -> Map[String, Float]
3549        let ty = MapType::new(PrimitiveType::String, PrimitiveType::Float).into();
3550        let map_value = value.coerce(&ty).expect("value should coerce");
3551        assert_eq!(
3552            map_value.to_string(),
3553            r#"{"foo": 1.000000, "bar": 2.000000, "baz": 3.000000}"#
3554        );
3555
3556        // Struct -> Struct
3557        let ty = StructType::new(
3558            "Bar",
3559            [
3560                ("foo", PrimitiveType::Float),
3561                ("bar", PrimitiveType::Float),
3562                ("baz", PrimitiveType::Float),
3563            ],
3564        )
3565        .into();
3566        let struct_value = value.coerce(&ty).expect("value should coerce");
3567        assert_eq!(
3568            struct_value.to_string(),
3569            r#"Bar {foo: 1.000000, bar: 2.000000, baz: 3.000000}"#
3570        );
3571
3572        // Struct -> Object
3573        let object_value = value.coerce(&Type::Object).expect("value should coerce");
3574        assert_eq!(
3575            object_value.to_string(),
3576            r#"object {foo: 1.000000, bar: 2.000000, baz: 3.000000}"#
3577        );
3578    }
3579
3580    #[test]
3581    fn struct_display() {
3582        let ty = StructType::new(
3583            "Foo",
3584            [
3585                ("foo", PrimitiveType::Float),
3586                ("bar", PrimitiveType::String),
3587                ("baz", PrimitiveType::Integer),
3588            ],
3589        );
3590        let value: Value = Struct::new(
3591            ty,
3592            [
3593                ("foo", Value::from(1.101)),
3594                ("bar", PrimitiveValue::new_string("foo").into()),
3595                ("baz", 1234.into()),
3596            ],
3597        )
3598        .expect("should create map value")
3599        .into();
3600        assert_eq!(
3601            value.to_string(),
3602            r#"Foo {foo: 1.101000, bar: "foo", baz: 1234}"#
3603        );
3604    }
3605}