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(members.into())))
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    pub fn new<S, V>(items: impl IntoIterator<Item = (S, V)>) -> Self
1795    where
1796        S: Into<String>,
1797        V: Into<Value>,
1798    {
1799        items
1800            .into_iter()
1801            .map(|(n, v)| {
1802                let n = n.into();
1803                let v = v.into();
1804                (n, v)
1805            })
1806            .collect::<IndexMap<_, _>>()
1807            .into()
1808    }
1809
1810    /// Returns an empty object.
1811    pub fn empty() -> Self {
1812        IndexMap::default().into()
1813    }
1814
1815    /// Creates an object from an iterator of V1 AST metadata items.
1816    pub fn from_v1_metadata<N: TreeNode>(
1817        items: impl Iterator<Item = v1::MetadataObjectItem<N>>,
1818    ) -> Self {
1819        items
1820            .map(|i| {
1821                (
1822                    i.name().text().to_string(),
1823                    Value::from_v1_metadata(&i.value()),
1824                )
1825            })
1826            .collect::<IndexMap<_, _>>()
1827            .into()
1828    }
1829
1830    /// Gets the type of the `Object` value.
1831    pub fn ty(&self) -> Type {
1832        Type::Object
1833    }
1834
1835    /// Iterates the members of the object.
1836    pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
1837        self.members
1838            .as_ref()
1839            .map(|m| Either::Left(m.iter().map(|(k, v)| (k.as_str(), v))))
1840            .unwrap_or(Either::Right(std::iter::empty()))
1841    }
1842
1843    /// Iterates the keys of the object.
1844    pub fn keys(&self) -> impl Iterator<Item = &str> {
1845        self.members
1846            .as_ref()
1847            .map(|m| Either::Left(m.keys().map(|k| k.as_str())))
1848            .unwrap_or(Either::Right(std::iter::empty()))
1849    }
1850
1851    /// Iterates the values of the object.
1852    pub fn values(&self) -> impl Iterator<Item = &Value> {
1853        self.members
1854            .as_ref()
1855            .map(|m| Either::Left(m.values()))
1856            .unwrap_or(Either::Right(std::iter::empty()))
1857    }
1858
1859    /// Determines if the object contains the given key.
1860    pub fn contains_key(&self, key: &str) -> bool {
1861        self.members
1862            .as_ref()
1863            .map(|m| m.contains_key(key))
1864            .unwrap_or(false)
1865    }
1866
1867    /// Gets a value from the object by key.
1868    pub fn get(&self, key: &str) -> Option<&Value> {
1869        self.members.as_ref().and_then(|m| m.get(key))
1870    }
1871
1872    /// Returns the number of members in the object.
1873    pub fn len(&self) -> usize {
1874        self.members.as_ref().map(|m| m.len()).unwrap_or(0)
1875    }
1876
1877    /// Returns `true` if the object has no members.
1878    pub fn is_empty(&self) -> bool {
1879        self.len() == 0
1880    }
1881}
1882
1883impl fmt::Display for Object {
1884    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1885        write!(f, "object {{")?;
1886
1887        for (i, (k, v)) in self.iter().enumerate() {
1888            if i > 0 {
1889                write!(f, ", ")?;
1890            }
1891
1892            write!(f, "{k}: {v}")?;
1893        }
1894
1895        write!(f, "}}")
1896    }
1897}
1898
1899impl From<IndexMap<String, Value>> for Object {
1900    fn from(members: IndexMap<String, Value>) -> Self {
1901        Self {
1902            members: if members.is_empty() {
1903                None
1904            } else {
1905                Some(Arc::new(members))
1906            },
1907        }
1908    }
1909}
1910
1911/// Represents a `Struct` value.
1912///
1913/// Structs are cheap to clone.
1914#[derive(Debug, Clone)]
1915pub struct Struct {
1916    /// The type of the struct value.
1917    ty: Type,
1918    /// The name of the struct.
1919    name: Arc<String>,
1920    /// The members of the struct value.
1921    pub(crate) members: Arc<IndexMap<String, Value>>,
1922}
1923
1924impl Struct {
1925    /// Creates a new struct value.
1926    ///
1927    /// Returns an error if the struct type does not contain a member of a given
1928    /// name or if a value does not coerce to the corresponding member's type.
1929    ///
1930    /// # Panics
1931    ///
1932    /// Panics if the given type is not a struct type.
1933    pub fn new<S, V>(ty: impl Into<Type>, members: impl IntoIterator<Item = (S, V)>) -> Result<Self>
1934    where
1935        S: Into<String>,
1936        V: Into<Value>,
1937    {
1938        let ty = ty.into();
1939        if let Type::Compound(CompoundType::Struct(ty), optional) = ty {
1940            let mut members = members
1941                .into_iter()
1942                .map(|(n, v)| {
1943                    let n = n.into();
1944                    let v = v.into();
1945                    let v = v
1946                        .coerce(ty.members().get(&n).ok_or_else(|| {
1947                            anyhow!("struct does not contain a member named `{n}`")
1948                        })?)
1949                        .with_context(|| format!("failed to coerce struct member `{n}`"))?;
1950                    Ok((n, v))
1951                })
1952                .collect::<Result<IndexMap<_, _>>>()?;
1953
1954            for (name, ty) in ty.members().iter() {
1955                // Check for optional members that should be set to `None`
1956                if ty.is_optional() {
1957                    if !members.contains_key(name) {
1958                        members.insert(name.clone(), Value::None);
1959                    }
1960                } else {
1961                    // Check for a missing required member
1962                    if !members.contains_key(name) {
1963                        bail!("missing a value for struct member `{name}`");
1964                    }
1965                }
1966            }
1967
1968            let name = ty.name().to_string();
1969            return Ok(Self {
1970                ty: Type::Compound(CompoundType::Struct(ty), optional),
1971                name: Arc::new(name),
1972                members: Arc::new(members),
1973            });
1974        }
1975
1976        panic!("type `{ty}` is not a struct type");
1977    }
1978
1979    /// Constructs a new struct without checking the given members conform to
1980    /// the given type.
1981    pub(crate) fn new_unchecked(
1982        ty: Type,
1983        name: Arc<String>,
1984        members: Arc<IndexMap<String, Value>>,
1985    ) -> Self {
1986        assert!(ty.as_struct().is_some());
1987        Self { ty, name, members }
1988    }
1989
1990    /// Gets the type of the `Struct` value.
1991    pub fn ty(&self) -> Type {
1992        self.ty.clone()
1993    }
1994
1995    /// Gets the name of the struct.
1996    pub fn name(&self) -> &Arc<String> {
1997        &self.name
1998    }
1999
2000    /// Iterates the members of the struct.
2001    pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
2002        self.members.iter().map(|(k, v)| (k.as_str(), v))
2003    }
2004
2005    /// Iterates the keys of the struct.
2006    pub fn keys(&self) -> impl Iterator<Item = &str> {
2007        self.members.keys().map(|k| k.as_str())
2008    }
2009
2010    /// Iterates the values of the struct.
2011    pub fn values(&self) -> impl Iterator<Item = &Value> {
2012        self.members.values()
2013    }
2014
2015    /// Determines if the struct contains the given member name.
2016    pub fn contains_key(&self, key: &str) -> bool {
2017        self.members.contains_key(key)
2018    }
2019
2020    /// Gets a value from the struct by member name.
2021    pub fn get(&self, key: &str) -> Option<&Value> {
2022        self.members.get(key)
2023    }
2024}
2025
2026impl fmt::Display for Struct {
2027    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2028        write!(f, "{name} {{", name = self.name)?;
2029
2030        for (i, (k, v)) in self.members.iter().enumerate() {
2031            if i > 0 {
2032                write!(f, ", ")?;
2033            }
2034
2035            write!(f, "{k}: {v}")?;
2036        }
2037
2038        write!(f, "}}")
2039    }
2040}
2041
2042/// Represents a compound value.
2043///
2044/// Compound values are cheap to clone.
2045#[derive(Debug, Clone)]
2046pub enum CompoundValue {
2047    /// The value is a `Pair` of values.
2048    Pair(Pair),
2049    /// The value is an `Array` of values.
2050    Array(Array),
2051    /// The value is a `Map` of values.
2052    Map(Map),
2053    /// The value is an `Object`.
2054    Object(Object),
2055    /// The value is a struct.
2056    Struct(Struct),
2057}
2058
2059impl CompoundValue {
2060    /// Gets the type of the compound value.
2061    pub fn ty(&self) -> Type {
2062        match self {
2063            CompoundValue::Pair(v) => v.ty(),
2064            CompoundValue::Array(v) => v.ty(),
2065            CompoundValue::Map(v) => v.ty(),
2066            CompoundValue::Object(v) => v.ty(),
2067            CompoundValue::Struct(v) => v.ty(),
2068        }
2069    }
2070
2071    /// Gets the value as a `Pair`.
2072    ///
2073    /// Returns `None` if the value is not a `Pair`.
2074    pub fn as_pair(&self) -> Option<&Pair> {
2075        match self {
2076            Self::Pair(v) => Some(v),
2077            _ => None,
2078        }
2079    }
2080
2081    /// Unwraps the value into a `Pair`.
2082    ///
2083    /// # Panics
2084    ///
2085    /// Panics if the value is not a `Pair`.
2086    pub fn unwrap_pair(self) -> Pair {
2087        match self {
2088            Self::Pair(v) => v,
2089            _ => panic!("value is not a pair"),
2090        }
2091    }
2092
2093    /// Gets the value as an `Array`.
2094    ///
2095    /// Returns `None` if the value is not an `Array`.
2096    pub fn as_array(&self) -> Option<&Array> {
2097        match self {
2098            Self::Array(v) => Some(v),
2099            _ => None,
2100        }
2101    }
2102
2103    /// Unwraps the value into an `Array`.
2104    ///
2105    /// # Panics
2106    ///
2107    /// Panics if the value is not an `Array`.
2108    pub fn unwrap_array(self) -> Array {
2109        match self {
2110            Self::Array(v) => v,
2111            _ => panic!("value is not an array"),
2112        }
2113    }
2114
2115    /// Gets the value as a `Map`.
2116    ///
2117    /// Returns `None` if the value is not a `Map`.
2118    pub fn as_map(&self) -> Option<&Map> {
2119        match self {
2120            Self::Map(v) => Some(v),
2121            _ => None,
2122        }
2123    }
2124
2125    /// Unwraps the value into a `Map`.
2126    ///
2127    /// # Panics
2128    ///
2129    /// Panics if the value is not a `Map`.
2130    pub fn unwrap_map(self) -> Map {
2131        match self {
2132            Self::Map(v) => v,
2133            _ => panic!("value is not a map"),
2134        }
2135    }
2136
2137    /// Gets the value as an `Object`.
2138    ///
2139    /// Returns `None` if the value is not an `Object`.
2140    pub fn as_object(&self) -> Option<&Object> {
2141        match self {
2142            Self::Object(v) => Some(v),
2143            _ => None,
2144        }
2145    }
2146
2147    /// Unwraps the value into an `Object`.
2148    ///
2149    /// # Panics
2150    ///
2151    /// Panics if the value is not an `Object`.
2152    pub fn unwrap_object(self) -> Object {
2153        match self {
2154            Self::Object(v) => v,
2155            _ => panic!("value is not an object"),
2156        }
2157    }
2158
2159    /// Gets the value as a `Struct`.
2160    ///
2161    /// Returns `None` if the value is not a `Struct`.
2162    pub fn as_struct(&self) -> Option<&Struct> {
2163        match self {
2164            Self::Struct(v) => Some(v),
2165            _ => None,
2166        }
2167    }
2168
2169    /// Unwraps the value into a `Struct`.
2170    ///
2171    /// # Panics
2172    ///
2173    /// Panics if the value is not a `Map`.
2174    pub fn unwrap_struct(self) -> Struct {
2175        match self {
2176            Self::Struct(v) => v,
2177            _ => panic!("value is not a struct"),
2178        }
2179    }
2180
2181    /// Compares two compound values for equality based on the WDL
2182    /// specification.
2183    ///
2184    /// Returns `None` if the two compound values cannot be compared for
2185    /// equality.
2186    pub fn equals(left: &Self, right: &Self) -> Option<bool> {
2187        // The values must have type equivalence to compare for compound values
2188        // Coercion doesn't take place for this check
2189        if left.ty() != right.ty() {
2190            return None;
2191        }
2192
2193        match (left, right) {
2194            (Self::Pair(left), Self::Pair(right)) => Some(
2195                Value::equals(left.left(), right.left())?
2196                    && Value::equals(left.right(), right.right())?,
2197            ),
2198            (CompoundValue::Array(left), CompoundValue::Array(right)) => Some(
2199                left.len() == right.len()
2200                    && left
2201                        .as_slice()
2202                        .iter()
2203                        .zip(right.as_slice())
2204                        .all(|(l, r)| Value::equals(l, r).unwrap_or(false)),
2205            ),
2206            (CompoundValue::Map(left), CompoundValue::Map(right)) => Some(
2207                left.len() == right.len()
2208                    // Maps are ordered, so compare via iteration
2209                    && left.iter().zip(right.iter()).all(|((lk, lv), (rk, rv))| {
2210                        match (lk, rk) {
2211                            (None, None) => {},
2212                            (Some(lk), Some(rk)) if lk == rk => {},
2213                            _ => return false
2214                        }
2215
2216                        Value::equals(lv, rv).unwrap_or(false)
2217                    }),
2218            ),
2219            (CompoundValue::Object(left), CompoundValue::Object(right)) => Some(
2220                left.len() == right.len()
2221                    && left.iter().all(|(k, left)| match right.get(k) {
2222                        Some(right) => Value::equals(left, right).unwrap_or(false),
2223                        None => false,
2224                    }),
2225            ),
2226            (
2227                CompoundValue::Struct(Struct { members: left, .. }),
2228                CompoundValue::Struct(Struct { members: right, .. }),
2229            ) => Some(
2230                left.len() == right.len()
2231                    && left.iter().all(|(k, left)| match right.get(k) {
2232                        Some(right) => Value::equals(left, right).unwrap_or(false),
2233                        None => false,
2234                    }),
2235            ),
2236            _ => None,
2237        }
2238    }
2239
2240    /// Visits each `File` or `Directory` value contained in this value.
2241    ///
2242    /// Note that paths may be specified as URLs.
2243    fn visit_paths(&self, cb: &mut impl FnMut(bool, &PrimitiveValue) -> Result<()>) -> Result<()> {
2244        match self {
2245            Self::Pair(pair) => {
2246                let ty = pair.ty.as_pair().expect("should be a pair type");
2247                pair.left().visit_paths(ty.left_type().is_optional(), cb)?;
2248                pair.right()
2249                    .visit_paths(ty.right_type().is_optional(), cb)?;
2250            }
2251            Self::Array(array) => {
2252                let ty = array.ty.as_array().expect("should be an array type");
2253                let optional = ty.element_type().is_optional();
2254                if let Some(elements) = &array.elements {
2255                    for v in elements.iter() {
2256                        v.visit_paths(optional, cb)?;
2257                    }
2258                }
2259            }
2260            Self::Map(map) => {
2261                let ty = map.ty.as_map().expect("should be a map type");
2262                let (key_optional, value_optional) =
2263                    (ty.key_type().is_optional(), ty.value_type().is_optional());
2264                if let Some(elements) = &map.elements {
2265                    for (k, v) in elements.iter() {
2266                        if let Some(k) = k {
2267                            k.visit_paths(key_optional, cb)?;
2268                        }
2269
2270                        v.visit_paths(value_optional, cb)?;
2271                    }
2272                }
2273            }
2274            Self::Object(object) => {
2275                if let Some(members) = &object.members {
2276                    for v in members.values() {
2277                        v.visit_paths(false, cb)?;
2278                    }
2279                }
2280            }
2281            Self::Struct(s) => {
2282                let ty = s.ty.as_struct().expect("should be a struct type");
2283                for (n, v) in s.members.iter() {
2284                    v.visit_paths(ty.members()[n].is_optional(), cb)?;
2285                }
2286            }
2287        }
2288
2289        Ok(())
2290    }
2291
2292    /// Mutably visits each `File` or `Directory` value contained in this value.
2293    ///
2294    /// If the provided callback returns `Ok(false)`, the `File` or `Directory`
2295    /// value will be replaced with `None`.
2296    ///
2297    /// Note that paths may be specified as URLs.
2298    fn visit_paths_mut(
2299        &mut self,
2300        cb: &mut impl FnMut(bool, &mut PrimitiveValue) -> Result<bool>,
2301    ) -> Result<()> {
2302        match self {
2303            Self::Pair(pair) => {
2304                let ty = pair.ty.as_pair().expect("should be a pair type");
2305                let (left_optional, right_optional) =
2306                    (ty.left_type().is_optional(), ty.right_type().is_optional());
2307                let values = Arc::make_mut(&mut pair.values);
2308                values.0.visit_paths_mut(left_optional, cb)?;
2309                values.1.visit_paths_mut(right_optional, cb)?;
2310            }
2311            Self::Array(array) => {
2312                let ty = array.ty.as_array().expect("should be an array type");
2313                let optional = ty.element_type().is_optional();
2314                if let Some(elements) = &mut array.elements {
2315                    for v in Arc::make_mut(elements) {
2316                        v.visit_paths_mut(optional, cb)?;
2317                    }
2318                }
2319            }
2320            Self::Map(map) => {
2321                let ty = map.ty.as_map().expect("should be a map type");
2322                let (key_optional, value_optional) =
2323                    (ty.key_type().is_optional(), ty.value_type().is_optional());
2324                if let Some(elements) = &mut map.elements {
2325                    if elements
2326                        .iter()
2327                        .find_map(|(k, _)| {
2328                            k.as_ref().map(|v| {
2329                                matches!(v, PrimitiveValue::File(_) | PrimitiveValue::Directory(_))
2330                            })
2331                        })
2332                        .unwrap_or(false)
2333                    {
2334                        // The key type contains a path, we need to rebuild the map to alter the
2335                        // keys
2336                        let elements = Arc::make_mut(elements);
2337                        let new = elements
2338                            .drain(..)
2339                            .map(|(mut k, mut v)| {
2340                                if let Some(v) = &mut k {
2341                                    if !v.visit_paths_mut(key_optional, cb)? {
2342                                        k = None;
2343                                    }
2344                                }
2345
2346                                v.visit_paths_mut(value_optional, cb)?;
2347                                Ok((k, v))
2348                            })
2349                            .collect::<Result<Vec<_>>>()?;
2350                        elements.extend(new);
2351                    } else {
2352                        // Otherwise, we can just mutable the values in place
2353                        for v in Arc::make_mut(elements).values_mut() {
2354                            v.visit_paths_mut(value_optional, cb)?;
2355                        }
2356                    }
2357                }
2358            }
2359            Self::Object(object) => {
2360                if let Some(members) = &mut object.members {
2361                    for v in Arc::make_mut(members).values_mut() {
2362                        v.visit_paths_mut(false, cb)?;
2363                    }
2364                }
2365            }
2366            Self::Struct(s) => {
2367                let ty = s.ty.as_struct().expect("should be a struct type");
2368                for (n, v) in Arc::make_mut(&mut s.members).iter_mut() {
2369                    v.visit_paths_mut(ty.members()[n].is_optional(), cb)?;
2370                }
2371            }
2372        }
2373
2374        Ok(())
2375    }
2376
2377    /// Creates a clone of the value, but makes the type required.
2378    fn clone_as_required(&self) -> Self {
2379        match self {
2380            Self::Pair(v) => Self::Pair(Pair {
2381                ty: v.ty.require(),
2382                values: v.values.clone(),
2383            }),
2384            Self::Array(v) => Self::Array(Array {
2385                ty: v.ty.require(),
2386                elements: v.elements.clone(),
2387            }),
2388            Self::Map(v) => Self::Map(Map {
2389                ty: v.ty.require(),
2390                elements: v.elements.clone(),
2391            }),
2392            Self::Object(_) => self.clone(),
2393            Self::Struct(v) => Self::Struct(Struct {
2394                ty: v.ty.require(),
2395                name: v.name.clone(),
2396                members: v.members.clone(),
2397            }),
2398        }
2399    }
2400
2401    /// Creates a clone of the value, but makes the type optional.
2402    fn clone_as_optional(&self) -> Self {
2403        match self {
2404            Self::Pair(v) => Self::Pair(Pair {
2405                ty: v.ty.optional(),
2406                values: v.values.clone(),
2407            }),
2408            Self::Array(v) => Self::Array(Array {
2409                ty: v.ty.optional(),
2410                elements: v.elements.clone(),
2411            }),
2412            Self::Map(v) => Self::Map(Map {
2413                ty: v.ty.optional(),
2414                elements: v.elements.clone(),
2415            }),
2416            Self::Object(_) => self.clone(),
2417            Self::Struct(v) => Self::Struct(Struct {
2418                ty: v.ty.optional(),
2419                name: v.name.clone(),
2420                members: v.members.clone(),
2421            }),
2422        }
2423    }
2424}
2425
2426impl fmt::Display for CompoundValue {
2427    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2428        match self {
2429            Self::Pair(v) => v.fmt(f),
2430            Self::Array(v) => v.fmt(f),
2431            Self::Map(v) => v.fmt(f),
2432            Self::Object(v) => v.fmt(f),
2433            Self::Struct(v) => v.fmt(f),
2434        }
2435    }
2436}
2437
2438impl Coercible for CompoundValue {
2439    fn coerce(&self, target: &Type) -> Result<Self> {
2440        if target.is_union() || target.is_none() || self.ty().eq(target) {
2441            return Ok(self.clone());
2442        }
2443
2444        if let Type::Compound(target_ty, _) = target {
2445            match (self, target_ty) {
2446                // Array[X] -> Array[Y](+) where X -> Y
2447                (Self::Array(v), CompoundType::Array(target_ty)) => {
2448                    // Don't allow coercion when the source is empty but the target has the
2449                    // non-empty qualifier
2450                    if v.is_empty() && target_ty.is_non_empty() {
2451                        bail!("cannot coerce empty array value to non-empty array type `{target}`",);
2452                    }
2453
2454                    return Ok(Self::Array(Array::new(
2455                        target.clone(),
2456                        v.as_slice().iter().cloned(),
2457                    )?));
2458                }
2459                // Map[W, Y] -> Map[X, Z] where W -> X and Y -> Z
2460                (Self::Map(v), CompoundType::Map(_)) => {
2461                    return Ok(Self::Map(Map::new(
2462                        target.clone(),
2463                        v.iter().map(|(k, v)| {
2464                            (k.clone().map(Into::into).unwrap_or(Value::None), v.clone())
2465                        }),
2466                    )?));
2467                }
2468                // Pair[W, Y] -> Pair[X, Z] where W -> X and Y -> Z
2469                (Self::Pair(v), CompoundType::Pair(_)) => {
2470                    return Ok(Self::Pair(Pair::new(
2471                        target.clone(),
2472                        v.values.0.clone(),
2473                        v.values.1.clone(),
2474                    )?));
2475                }
2476                // Map[String, Y] -> Struct
2477                (Self::Map(v), CompoundType::Struct(target_ty)) => {
2478                    let len = v.len();
2479                    let expected_len = target_ty.members().len();
2480
2481                    if len != expected_len {
2482                        bail!(
2483                            "cannot coerce a map of {len} element{s1} to struct type `{target}` \
2484                             as the struct has {expected_len} member{s2}",
2485                            s1 = if len == 1 { "" } else { "s" },
2486                            s2 = if expected_len == 1 { "" } else { "s" }
2487                        );
2488                    }
2489
2490                    return Ok(Self::Struct(Struct {
2491                        ty: target.clone(),
2492                        name: target_ty.name().clone(),
2493                        members: Arc::new(
2494                            v.iter()
2495                                .map(|(k, v)| {
2496                                    let k: String = k
2497                                        .as_ref()
2498                                        .and_then(|k| k.as_string())
2499                                        .with_context(|| {
2500                                            format!(
2501                                                "cannot coerce a map with a non-string key type \
2502                                                 to struct type `{target}`"
2503                                            )
2504                                        })?
2505                                        .to_string();
2506                                    let ty = target_ty.members().get(&k).with_context(|| {
2507                                        format!(
2508                                            "cannot coerce a map with key `{k}` to struct type \
2509                                             `{target}` as the struct does not contain a member \
2510                                             with that name"
2511                                        )
2512                                    })?;
2513                                    let v = v.coerce(ty).with_context(|| {
2514                                        format!("failed to coerce value of map key `{k}")
2515                                    })?;
2516                                    Ok((k, v))
2517                                })
2518                                .collect::<Result<_>>()?,
2519                        ),
2520                    }));
2521                }
2522                // Struct -> Map[String, Y]
2523                // Object -> Map[String, Y]
2524                (Self::Struct(Struct { members, .. }), CompoundType::Map(map_ty)) => {
2525                    if map_ty.key_type().as_primitive() != Some(PrimitiveType::String) {
2526                        bail!(
2527                            "cannot coerce a struct or object to type `{target}` as it requires a \
2528                             `String` key type"
2529                        );
2530                    }
2531
2532                    let value_ty = map_ty.value_type();
2533                    return Ok(Self::Map(Map::new_unchecked(
2534                        target.clone(),
2535                        members
2536                            .iter()
2537                            .map(|(n, v)| {
2538                                let v = v
2539                                    .coerce(value_ty)
2540                                    .with_context(|| format!("failed to coerce member `{n}`"))?;
2541                                Ok((PrimitiveValue::new_string(n).into(), v))
2542                            })
2543                            .collect::<Result<_>>()?,
2544                    )));
2545                }
2546                (Self::Object(object), CompoundType::Map(map_ty)) => {
2547                    if map_ty.key_type().as_primitive() != Some(PrimitiveType::String) {
2548                        bail!(
2549                            "cannot coerce a struct or object to type `{target}` as it requires a \
2550                             `String` key type",
2551                        );
2552                    }
2553
2554                    let value_ty = map_ty.value_type();
2555                    return Ok(Self::Map(Map::new_unchecked(
2556                        target.clone(),
2557                        object
2558                            .iter()
2559                            .map(|(n, v)| {
2560                                let v = v
2561                                    .coerce(value_ty)
2562                                    .with_context(|| format!("failed to coerce member `{n}`"))?;
2563                                Ok((PrimitiveValue::new_string(n).into(), v))
2564                            })
2565                            .collect::<Result<_>>()?,
2566                    )));
2567                }
2568                // Object -> Struct
2569                (Self::Object(v), CompoundType::Struct(_)) => {
2570                    return Ok(Self::Struct(Struct::new(
2571                        target.clone(),
2572                        v.iter().map(|(k, v)| (k, v.clone())),
2573                    )?));
2574                }
2575                // Struct -> Struct
2576                (Self::Struct(v), CompoundType::Struct(struct_ty)) => {
2577                    let len = v.members.len();
2578                    let expected_len = struct_ty.members().len();
2579
2580                    if len != expected_len {
2581                        bail!(
2582                            "cannot coerce a struct of {len} members{s1} to struct type \
2583                             `{target}` as the target struct has {expected_len} member{s2}",
2584                            s1 = if len == 1 { "" } else { "s" },
2585                            s2 = if expected_len == 1 { "" } else { "s" }
2586                        );
2587                    }
2588
2589                    return Ok(Self::Struct(Struct {
2590                        ty: target.clone(),
2591                        name: struct_ty.name().clone(),
2592                        members: Arc::new(
2593                            v.members
2594                                .iter()
2595                                .map(|(k, v)| {
2596                                    let ty = struct_ty.members().get(k).ok_or_else(|| {
2597                                        anyhow!(
2598                                            "cannot coerce a struct with member `{k}` to struct \
2599                                             type `{target}` as the target struct does not \
2600                                             contain a member with that name",
2601                                        )
2602                                    })?;
2603                                    let v = v.coerce(ty).with_context(|| {
2604                                        format!("failed to coerce member `{k}`")
2605                                    })?;
2606                                    Ok((k.clone(), v))
2607                                })
2608                                .collect::<Result<_>>()?,
2609                        ),
2610                    }));
2611                }
2612                _ => {}
2613            }
2614        }
2615
2616        if let Type::Object = target {
2617            match self {
2618                // Map[String, Y] -> Object
2619                Self::Map(v) => {
2620                    return Ok(Self::Object(
2621                        v.iter()
2622                            .map(|(k, v)| {
2623                                let k = k
2624                                    .as_ref()
2625                                    .and_then(|k| k.as_string())
2626                                    .context(
2627                                        "cannot coerce a map with a non-string key type to type \
2628                                         `Object`",
2629                                    )?
2630                                    .to_string();
2631                                Ok((k, v.clone()))
2632                            })
2633                            .collect::<Result<IndexMap<_, _>>>()?
2634                            .into(),
2635                    ));
2636                }
2637                // Struct -> Object
2638                Self::Struct(v) => {
2639                    return Ok(Self::Object(Object {
2640                        members: Some(v.members.clone()),
2641                    }));
2642                }
2643                _ => {}
2644            };
2645        }
2646
2647        bail!(
2648            "cannot coerce a value of type `{ty}` to type `{target}`",
2649            ty = self.ty()
2650        );
2651    }
2652}
2653
2654impl From<Pair> for CompoundValue {
2655    fn from(value: Pair) -> Self {
2656        Self::Pair(value)
2657    }
2658}
2659
2660impl From<Array> for CompoundValue {
2661    fn from(value: Array) -> Self {
2662        Self::Array(value)
2663    }
2664}
2665
2666impl From<Map> for CompoundValue {
2667    fn from(value: Map) -> Self {
2668        Self::Map(value)
2669    }
2670}
2671
2672impl From<Object> for CompoundValue {
2673    fn from(value: Object) -> Self {
2674        Self::Object(value)
2675    }
2676}
2677
2678impl From<Struct> for CompoundValue {
2679    fn from(value: Struct) -> Self {
2680        Self::Struct(value)
2681    }
2682}
2683
2684impl serde::Serialize for CompoundValue {
2685    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2686    where
2687        S: serde::Serializer,
2688    {
2689        use serde::ser::Error;
2690
2691        match self {
2692            Self::Pair(_) => Err(S::Error::custom("a pair cannot be serialized")),
2693            Self::Array(v) => {
2694                let mut s = serializer.serialize_seq(Some(v.len()))?;
2695                for v in v.as_slice() {
2696                    s.serialize_element(v)?;
2697                }
2698
2699                s.end()
2700            }
2701            Self::Map(v) => {
2702                if !v
2703                    .ty()
2704                    .as_map()
2705                    .expect("type should be a map")
2706                    .key_type()
2707                    .is_coercible_to(&PrimitiveType::String.into())
2708                {
2709                    return Err(S::Error::custom(
2710                        "only maps with `String` key types may be serialized",
2711                    ));
2712                }
2713
2714                let mut s = serializer.serialize_map(Some(v.len()))?;
2715                for (k, v) in v.iter() {
2716                    s.serialize_entry(k, v)?;
2717                }
2718
2719                s.end()
2720            }
2721            Self::Object(object) => {
2722                let mut s = serializer.serialize_map(Some(object.len()))?;
2723                for (k, v) in object.iter() {
2724                    s.serialize_entry(k, v)?;
2725                }
2726
2727                s.end()
2728            }
2729            Self::Struct(Struct { members, .. }) => {
2730                let mut s = serializer.serialize_map(Some(members.len()))?;
2731                for (k, v) in members.iter() {
2732                    s.serialize_entry(k, v)?;
2733                }
2734
2735                s.end()
2736            }
2737        }
2738    }
2739}
2740
2741/// Immutable data for task values.
2742#[derive(Debug)]
2743struct TaskData {
2744    /// The name of the task.
2745    name: Arc<String>,
2746    /// The id of the task.
2747    id: Arc<String>,
2748    /// The container of the task.
2749    container: Option<Arc<String>>,
2750    /// The allocated number of cpus for the task.
2751    cpu: f64,
2752    /// The allocated memory (in bytes) for the task.
2753    memory: i64,
2754    /// The GPU allocations for the task.
2755    ///
2756    /// An array with one specification per allocated GPU; the specification is
2757    /// execution engine-specific.
2758    gpu: Array,
2759    /// The FPGA allocations for the task.
2760    ///
2761    /// An array with one specification per allocated FPGA; the specification is
2762    /// execution engine-specific.
2763    fpga: Array,
2764    /// The disk allocations for the task.
2765    ///
2766    /// A map with one entry for each disk mount point.
2767    ///
2768    /// The key is the mount point and the value is the initial amount of disk
2769    /// space allocated, in bytes.
2770    disks: Map,
2771    /// The time by which the task must be completed, as a Unix time stamp.
2772    ///
2773    /// A value of `None` indicates there is no deadline.
2774    end_time: Option<i64>,
2775    /// The task's `meta` section as an object.
2776    meta: Object,
2777    /// The tasks's `parameter_meta` section as an object.
2778    parameter_meta: Object,
2779    /// The task's extension metadata.
2780    ext: Object,
2781}
2782
2783/// Represents a value for `task` variables in WDL 1.2.
2784///
2785/// Task values are cheap to clone.
2786#[derive(Debug, Clone)]
2787pub struct TaskValue {
2788    /// The immutable data for task values.
2789    data: Arc<TaskData>,
2790    /// The current task attempt count.
2791    ///
2792    /// The value must be 0 the first time the task is executed and incremented
2793    /// by 1 each time the task is retried (if any).
2794    attempt: i64,
2795    /// The task's return code.
2796    ///
2797    /// Initially set to `None`, but set after task execution completes.
2798    return_code: Option<i64>,
2799}
2800
2801impl TaskValue {
2802    /// Constructs a new task value with the given name and identifier.
2803    pub(crate) fn new_v1<N: TreeNode>(
2804        name: impl Into<String>,
2805        id: impl Into<String>,
2806        definition: &v1::TaskDefinition<N>,
2807        constraints: TaskExecutionConstraints,
2808        attempt: i64,
2809    ) -> Self {
2810        Self {
2811            data: Arc::new(TaskData {
2812                name: Arc::new(name.into()),
2813                id: Arc::new(id.into()),
2814                container: constraints.container.map(Into::into),
2815                cpu: constraints.cpu,
2816                memory: constraints.memory,
2817                gpu: Array::new_unchecked(
2818                    ANALYSIS_STDLIB.array_string_type().clone(),
2819                    constraints
2820                        .gpu
2821                        .into_iter()
2822                        .map(|v| PrimitiveValue::new_string(v).into())
2823                        .collect(),
2824                ),
2825                fpga: Array::new_unchecked(
2826                    ANALYSIS_STDLIB.array_string_type().clone(),
2827                    constraints
2828                        .fpga
2829                        .into_iter()
2830                        .map(|v| PrimitiveValue::new_string(v).into())
2831                        .collect(),
2832                ),
2833                disks: Map::new_unchecked(
2834                    ANALYSIS_STDLIB.map_string_int_type().clone(),
2835                    constraints
2836                        .disks
2837                        .into_iter()
2838                        .map(|(k, v)| (Some(PrimitiveValue::new_string(k)), v.into()))
2839                        .collect(),
2840                ),
2841                end_time: None,
2842                meta: definition
2843                    .metadata()
2844                    .map(|s| Object::from_v1_metadata(s.items()))
2845                    .unwrap_or_else(Object::empty),
2846                parameter_meta: definition
2847                    .parameter_metadata()
2848                    .map(|s| Object::from_v1_metadata(s.items()))
2849                    .unwrap_or_else(Object::empty),
2850                ext: Object::empty(),
2851            }),
2852            attempt,
2853            return_code: None,
2854        }
2855    }
2856
2857    /// Gets the task name.
2858    pub fn name(&self) -> &Arc<String> {
2859        &self.data.name
2860    }
2861
2862    /// Gets the unique ID of the task.
2863    pub fn id(&self) -> &Arc<String> {
2864        &self.data.id
2865    }
2866
2867    /// Gets the container in which the task is executing.
2868    pub fn container(&self) -> Option<&Arc<String>> {
2869        self.data.container.as_ref()
2870    }
2871
2872    /// Gets the allocated number of cpus for the task.
2873    pub fn cpu(&self) -> f64 {
2874        self.data.cpu
2875    }
2876
2877    /// Gets the allocated memory (in bytes) for the task.
2878    pub fn memory(&self) -> i64 {
2879        self.data.memory
2880    }
2881
2882    /// Gets the GPU allocations for the task.
2883    ///
2884    /// An array with one specification per allocated GPU; the specification is
2885    /// execution engine-specific.
2886    pub fn gpu(&self) -> &Array {
2887        &self.data.gpu
2888    }
2889
2890    /// Gets the FPGA allocations for the task.
2891    ///
2892    /// An array with one specification per allocated FPGA; the specification is
2893    /// execution engine-specific.
2894    pub fn fpga(&self) -> &Array {
2895        &self.data.fpga
2896    }
2897
2898    /// Gets the disk allocations for the task.
2899    ///
2900    /// A map with one entry for each disk mount point.
2901    ///
2902    /// The key is the mount point and the value is the initial amount of disk
2903    /// space allocated, in bytes.
2904    pub fn disks(&self) -> &Map {
2905        &self.data.disks
2906    }
2907
2908    /// Gets current task attempt count.
2909    ///
2910    /// The value must be 0 the first time the task is executed and incremented
2911    /// by 1 each time the task is retried (if any).
2912    pub fn attempt(&self) -> i64 {
2913        self.attempt
2914    }
2915
2916    /// Gets the time by which the task must be completed, as a Unix time stamp.
2917    ///
2918    /// A value of `None` indicates there is no deadline.
2919    pub fn end_time(&self) -> Option<i64> {
2920        self.data.end_time
2921    }
2922
2923    /// Gets the task's return code.
2924    ///
2925    /// Initially set to `None`, but set after task execution completes.
2926    pub fn return_code(&self) -> Option<i64> {
2927        self.return_code
2928    }
2929
2930    /// Gets the task's `meta` section as an object.
2931    pub fn meta(&self) -> &Object {
2932        &self.data.meta
2933    }
2934
2935    /// Gets the tasks's `parameter_meta` section as an object.
2936    pub fn parameter_meta(&self) -> &Object {
2937        &self.data.parameter_meta
2938    }
2939
2940    /// Gets the task's extension metadata.
2941    pub fn ext(&self) -> &Object {
2942        &self.data.ext
2943    }
2944
2945    /// Sets the return code after the task execution has completed.
2946    pub(crate) fn set_return_code(&mut self, code: i32) {
2947        self.return_code = Some(code as i64);
2948    }
2949
2950    /// Sets the attempt number for the task.
2951    pub(crate) fn set_attempt(&mut self, attempt: i64) {
2952        self.attempt = attempt;
2953    }
2954
2955    /// Accesses a field of the task value by name.
2956    ///
2957    /// Returns `None` if the name is not a known field name.
2958    pub fn field(&self, name: &str) -> Option<Value> {
2959        match name {
2960            n if n == TASK_FIELD_NAME => {
2961                Some(PrimitiveValue::String(self.data.name.clone()).into())
2962            }
2963            n if n == TASK_FIELD_ID => Some(PrimitiveValue::String(self.data.id.clone()).into()),
2964            n if n == TASK_FIELD_CONTAINER => Some(
2965                self.data
2966                    .container
2967                    .clone()
2968                    .map(|c| PrimitiveValue::String(c).into())
2969                    .unwrap_or(Value::None),
2970            ),
2971            n if n == TASK_FIELD_CPU => Some(self.data.cpu.into()),
2972            n if n == TASK_FIELD_MEMORY => Some(self.data.memory.into()),
2973            n if n == TASK_FIELD_GPU => Some(self.data.gpu.clone().into()),
2974            n if n == TASK_FIELD_FPGA => Some(self.data.fpga.clone().into()),
2975            n if n == TASK_FIELD_DISKS => Some(self.data.disks.clone().into()),
2976            n if n == TASK_FIELD_ATTEMPT => Some(self.attempt.into()),
2977            n if n == TASK_FIELD_END_TIME => {
2978                Some(self.data.end_time.map(Into::into).unwrap_or(Value::None))
2979            }
2980            n if n == TASK_FIELD_RETURN_CODE => {
2981                Some(self.return_code.map(Into::into).unwrap_or(Value::None))
2982            }
2983            n if n == TASK_FIELD_META => Some(self.data.meta.clone().into()),
2984            n if n == TASK_FIELD_PARAMETER_META => Some(self.data.parameter_meta.clone().into()),
2985            n if n == TASK_FIELD_EXT => Some(self.data.ext.clone().into()),
2986            _ => None,
2987        }
2988    }
2989}
2990
2991/// Represents a hints value from a WDL 1.2 hints section.
2992///
2993/// Hints values are cheap to clone.
2994#[derive(Debug, Clone)]
2995pub struct HintsValue(Object);
2996
2997impl HintsValue {
2998    /// Converts the hints value to an object.
2999    pub fn as_object(&self) -> &Object {
3000        &self.0
3001    }
3002}
3003
3004impl fmt::Display for HintsValue {
3005    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3006        write!(f, "hints {{")?;
3007
3008        for (i, (k, v)) in self.0.iter().enumerate() {
3009            if i > 0 {
3010                write!(f, ", ")?;
3011            }
3012
3013            write!(f, "{k}: {v}")?;
3014        }
3015
3016        write!(f, "}}")
3017    }
3018}
3019
3020impl From<Object> for HintsValue {
3021    fn from(value: Object) -> Self {
3022        Self(value)
3023    }
3024}
3025
3026/// Represents an input value from a WDL 1.2 hints section.
3027///
3028/// Input values are cheap to clone.
3029#[derive(Debug, Clone)]
3030pub struct InputValue(Object);
3031
3032impl InputValue {
3033    /// Converts the input value to an object.
3034    pub fn as_object(&self) -> &Object {
3035        &self.0
3036    }
3037}
3038
3039impl fmt::Display for InputValue {
3040    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3041        write!(f, "input {{")?;
3042
3043        for (i, (k, v)) in self.0.iter().enumerate() {
3044            if i > 0 {
3045                write!(f, ", ")?;
3046            }
3047
3048            write!(f, "{k}: {v}")?;
3049        }
3050
3051        write!(f, "}}")
3052    }
3053}
3054
3055impl From<Object> for InputValue {
3056    fn from(value: Object) -> Self {
3057        Self(value)
3058    }
3059}
3060
3061/// Represents an output value from a WDL 1.2 hints section.
3062///
3063/// Output values are cheap to clone.
3064#[derive(Debug, Clone)]
3065pub struct OutputValue(Object);
3066
3067impl OutputValue {
3068    /// Converts the output value to an object.
3069    pub fn as_object(&self) -> &Object {
3070        &self.0
3071    }
3072}
3073
3074impl fmt::Display for OutputValue {
3075    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3076        write!(f, "output {{")?;
3077
3078        for (i, (k, v)) in self.0.iter().enumerate() {
3079            if i > 0 {
3080                write!(f, ", ")?;
3081            }
3082
3083            write!(f, "{k}: {v}")?;
3084        }
3085
3086        write!(f, "}}")
3087    }
3088}
3089
3090impl From<Object> for OutputValue {
3091    fn from(value: Object) -> Self {
3092        Self(value)
3093    }
3094}
3095
3096/// Represents the outputs of a call.
3097///
3098/// Call values are cheap to clone.
3099#[derive(Debug, Clone)]
3100pub struct CallValue {
3101    /// The type of the call.
3102    ty: CallType,
3103    /// The outputs of the call.
3104    outputs: Arc<Outputs>,
3105}
3106
3107impl CallValue {
3108    /// Constructs a new call value without checking the outputs conform to the
3109    /// call type.
3110    pub(crate) fn new_unchecked(ty: CallType, outputs: Arc<Outputs>) -> Self {
3111        Self { ty, outputs }
3112    }
3113
3114    /// Gets the type of the call.
3115    pub fn ty(&self) -> &CallType {
3116        &self.ty
3117    }
3118
3119    /// Gets the outputs of the call.
3120    pub fn outputs(&self) -> &Outputs {
3121        self.outputs.as_ref()
3122    }
3123}
3124
3125impl fmt::Display for CallValue {
3126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3127        write!(f, "call output {{")?;
3128
3129        for (i, (k, v)) in self.outputs.iter().enumerate() {
3130            if i > 0 {
3131                write!(f, ", ")?;
3132            }
3133
3134            write!(f, "{k}: {v}")?;
3135        }
3136
3137        write!(f, "}}")
3138    }
3139}
3140
3141#[cfg(test)]
3142mod test {
3143    use approx::assert_relative_eq;
3144    use pretty_assertions::assert_eq;
3145    use wdl_analysis::types::ArrayType;
3146    use wdl_analysis::types::MapType;
3147    use wdl_analysis::types::PairType;
3148    use wdl_analysis::types::StructType;
3149
3150    use super::*;
3151
3152    #[test]
3153    fn boolean_coercion() {
3154        // Boolean -> Boolean
3155        assert_eq!(
3156            Value::from(false)
3157                .coerce(&PrimitiveType::Boolean.into())
3158                .expect("should coerce")
3159                .unwrap_boolean(),
3160            Value::from(false).unwrap_boolean()
3161        );
3162        // Boolean -> String (invalid)
3163        assert_eq!(
3164            format!(
3165                "{e:?}",
3166                e = Value::from(true)
3167                    .coerce(&PrimitiveType::String.into())
3168                    .unwrap_err()
3169            ),
3170            "cannot coerce type `Boolean` to type `String`"
3171        );
3172    }
3173
3174    #[test]
3175    fn boolean_display() {
3176        assert_eq!(Value::from(false).to_string(), "false");
3177        assert_eq!(Value::from(true).to_string(), "true");
3178    }
3179
3180    #[test]
3181    fn integer_coercion() {
3182        // Int -> Int
3183        assert_eq!(
3184            Value::from(12345)
3185                .coerce(&PrimitiveType::Integer.into())
3186                .expect("should coerce")
3187                .unwrap_integer(),
3188            Value::from(12345).unwrap_integer()
3189        );
3190        // Int -> Float
3191        assert_relative_eq!(
3192            Value::from(12345)
3193                .coerce(&PrimitiveType::Float.into())
3194                .expect("should coerce")
3195                .unwrap_float(),
3196            Value::from(12345.0).unwrap_float()
3197        );
3198        // Int -> Boolean (invalid)
3199        assert_eq!(
3200            format!(
3201                "{e:?}",
3202                e = Value::from(12345)
3203                    .coerce(&PrimitiveType::Boolean.into())
3204                    .unwrap_err()
3205            ),
3206            "cannot coerce type `Int` to type `Boolean`"
3207        );
3208    }
3209
3210    #[test]
3211    fn integer_display() {
3212        assert_eq!(Value::from(12345).to_string(), "12345");
3213        assert_eq!(Value::from(-12345).to_string(), "-12345");
3214    }
3215
3216    #[test]
3217    fn float_coercion() {
3218        // Float -> Float
3219        assert_relative_eq!(
3220            Value::from(12345.0)
3221                .coerce(&PrimitiveType::Float.into())
3222                .expect("should coerce")
3223                .unwrap_float(),
3224            Value::from(12345.0).unwrap_float()
3225        );
3226        // Float -> Int (invalid)
3227        assert_eq!(
3228            format!(
3229                "{e:?}",
3230                e = Value::from(12345.0)
3231                    .coerce(&PrimitiveType::Integer.into())
3232                    .unwrap_err()
3233            ),
3234            "cannot coerce type `Float` to type `Int`"
3235        );
3236    }
3237
3238    #[test]
3239    fn float_display() {
3240        assert_eq!(Value::from(12345.12345).to_string(), "12345.123450");
3241        assert_eq!(Value::from(-12345.12345).to_string(), "-12345.123450");
3242    }
3243
3244    #[test]
3245    fn string_coercion() {
3246        let value = PrimitiveValue::new_string("foo");
3247        // String -> String
3248        assert_eq!(
3249            value
3250                .coerce(&PrimitiveType::String.into())
3251                .expect("should coerce"),
3252            value
3253        );
3254        // String -> File
3255        assert_eq!(
3256            value
3257                .coerce(&PrimitiveType::File.into())
3258                .expect("should coerce"),
3259            PrimitiveValue::File(value.as_string().expect("should be string").clone())
3260        );
3261        // String -> Directory
3262        assert_eq!(
3263            value
3264                .coerce(&PrimitiveType::Directory.into())
3265                .expect("should coerce"),
3266            PrimitiveValue::Directory(value.as_string().expect("should be string").clone())
3267        );
3268        // String -> Boolean (invalid)
3269        assert_eq!(
3270            format!(
3271                "{e:?}",
3272                e = value.coerce(&PrimitiveType::Boolean.into()).unwrap_err()
3273            ),
3274            "cannot coerce type `String` to type `Boolean`"
3275        );
3276    }
3277
3278    #[test]
3279    fn string_display() {
3280        let value = PrimitiveValue::new_string("hello world!");
3281        assert_eq!(value.to_string(), "\"hello world!\"");
3282    }
3283
3284    #[test]
3285    fn file_coercion() {
3286        let value = PrimitiveValue::new_file("foo");
3287
3288        // File -> File
3289        assert_eq!(
3290            value
3291                .coerce(&PrimitiveType::File.into())
3292                .expect("should coerce"),
3293            value
3294        );
3295        // File -> String
3296        assert_eq!(
3297            value
3298                .coerce(&PrimitiveType::String.into())
3299                .expect("should coerce"),
3300            PrimitiveValue::String(value.as_file().expect("should be file").clone())
3301        );
3302        // File -> Directory (invalid)
3303        assert_eq!(
3304            format!(
3305                "{e:?}",
3306                e = value.coerce(&PrimitiveType::Directory.into()).unwrap_err()
3307            ),
3308            "cannot coerce type `File` to type `Directory`"
3309        );
3310    }
3311
3312    #[test]
3313    fn file_display() {
3314        let value = PrimitiveValue::new_file("/foo/bar/baz.txt");
3315        assert_eq!(value.to_string(), "\"/foo/bar/baz.txt\"");
3316    }
3317
3318    #[test]
3319    fn directory_coercion() {
3320        let value = PrimitiveValue::new_directory("foo");
3321
3322        // Directory -> Directory
3323        assert_eq!(
3324            value
3325                .coerce(&PrimitiveType::Directory.into())
3326                .expect("should coerce"),
3327            value
3328        );
3329        // Directory -> String
3330        assert_eq!(
3331            value
3332                .coerce(&PrimitiveType::String.into())
3333                .expect("should coerce"),
3334            PrimitiveValue::String(value.as_directory().expect("should be directory").clone())
3335        );
3336        // Directory -> File (invalid)
3337        assert_eq!(
3338            format!(
3339                "{e:?}",
3340                e = value.coerce(&PrimitiveType::File.into()).unwrap_err()
3341            ),
3342            "cannot coerce type `Directory` to type `File`"
3343        );
3344    }
3345
3346    #[test]
3347    fn directory_display() {
3348        let value = PrimitiveValue::new_directory("/foo/bar/baz");
3349        assert_eq!(value.to_string(), "\"/foo/bar/baz\"");
3350    }
3351
3352    #[test]
3353    fn none_coercion() {
3354        // None -> String?
3355        assert!(
3356            Value::None
3357                .coerce(&Type::from(PrimitiveType::String).optional())
3358                .expect("should coerce")
3359                .is_none(),
3360        );
3361
3362        // None -> String (invalid)
3363        assert_eq!(
3364            format!(
3365                "{e:?}",
3366                e = Value::None
3367                    .coerce(&PrimitiveType::String.into())
3368                    .unwrap_err()
3369            ),
3370            "cannot coerce `None` to non-optional type `String`"
3371        );
3372    }
3373
3374    #[test]
3375    fn none_display() {
3376        assert_eq!(Value::None.to_string(), "None");
3377    }
3378
3379    #[test]
3380    fn array_coercion() {
3381        let src_ty: Type = ArrayType::new(PrimitiveType::Integer).into();
3382        let target_ty: Type = ArrayType::new(PrimitiveType::Float).into();
3383
3384        // Array[Int] -> Array[Float]
3385        let src: CompoundValue = Array::new(src_ty, [1, 2, 3])
3386            .expect("should create array value")
3387            .into();
3388        let target = src.coerce(&target_ty).expect("should coerce");
3389        assert_eq!(
3390            target.unwrap_array().to_string(),
3391            "[1.000000, 2.000000, 3.000000]"
3392        );
3393
3394        // Array[Int] -> Array[String] (invalid)
3395        let target_ty: Type = ArrayType::new(PrimitiveType::String).into();
3396        assert_eq!(
3397            format!("{e:?}", e = src.coerce(&target_ty).unwrap_err()),
3398            r#"failed to coerce array element at index 0
3399
3400Caused by:
3401    cannot coerce type `Int` to type `String`"#
3402        );
3403    }
3404
3405    #[test]
3406    fn non_empty_array_coercion() {
3407        let ty: Type = ArrayType::new(PrimitiveType::String).into();
3408        let target_ty: Type = ArrayType::non_empty(PrimitiveType::String).into();
3409
3410        // Array[String] (non-empty) -> Array[String]+
3411        let string = PrimitiveValue::new_string("foo");
3412        let value: Value = Array::new(ty.clone(), [string])
3413            .expect("should create array")
3414            .into();
3415        assert!(value.coerce(&target_ty).is_ok(), "should coerce");
3416
3417        // Array[String] (empty) -> Array[String]+ (invalid)
3418        let value: Value = Array::new::<Value>(ty, [])
3419            .expect("should create array")
3420            .into();
3421        assert_eq!(
3422            format!("{e:?}", e = value.coerce(&target_ty).unwrap_err()),
3423            "cannot coerce empty array value to non-empty array type `Array[String]+`"
3424        );
3425    }
3426
3427    #[test]
3428    fn array_display() {
3429        let ty: Type = ArrayType::new(PrimitiveType::Integer).into();
3430        let value: Value = Array::new(ty, [1, 2, 3])
3431            .expect("should create array")
3432            .into();
3433
3434        assert_eq!(value.to_string(), "[1, 2, 3]");
3435    }
3436
3437    #[test]
3438    fn map_coerce() {
3439        let key1 = PrimitiveValue::new_file("foo");
3440        let value1 = PrimitiveValue::new_string("bar");
3441        let key2 = PrimitiveValue::new_file("baz");
3442        let value2 = PrimitiveValue::new_string("qux");
3443
3444        let ty = MapType::new(PrimitiveType::File, PrimitiveType::String);
3445        let value: Value = Map::new(ty, [(key1, value1), (key2, value2)])
3446            .expect("should create map value")
3447            .into();
3448
3449        // Map[File, String] -> Map[String, File]
3450        let ty = MapType::new(PrimitiveType::String, PrimitiveType::File).into();
3451        let value = value.coerce(&ty).expect("value should coerce");
3452        assert_eq!(value.to_string(), r#"{"foo": "bar", "baz": "qux"}"#);
3453
3454        // Map[String, File] -> Map[Int, File] (invalid)
3455        let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::File).into();
3456        assert_eq!(
3457            format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3458            r#"failed to coerce map key for element at index 0
3459
3460Caused by:
3461    cannot coerce type `String` to type `Int`"#
3462        );
3463
3464        // Map[String, File] -> Map[String, Int] (invalid)
3465        let ty = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
3466        assert_eq!(
3467            format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3468            r#"failed to coerce map value for element at index 0
3469
3470Caused by:
3471    cannot coerce type `File` to type `Int`"#
3472        );
3473
3474        // Map[String, File] -> Struct
3475        let ty = StructType::new(
3476            "Foo",
3477            [("foo", PrimitiveType::File), ("baz", PrimitiveType::File)],
3478        )
3479        .into();
3480        let struct_value = value.coerce(&ty).expect("value should coerce");
3481        assert_eq!(struct_value.to_string(), r#"Foo {foo: "bar", baz: "qux"}"#);
3482
3483        // Map[String, File] -> Struct (invalid)
3484        let ty = StructType::new(
3485            "Foo",
3486            [
3487                ("foo", PrimitiveType::File),
3488                ("baz", PrimitiveType::File),
3489                ("qux", PrimitiveType::File),
3490            ],
3491        )
3492        .into();
3493        assert_eq!(
3494            format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3495            "cannot coerce a map of 2 elements to struct type `Foo` as the struct has 3 members"
3496        );
3497
3498        // Map[String, File] -> Object
3499        let object_value = value.coerce(&Type::Object).expect("value should coerce");
3500        assert_eq!(
3501            object_value.to_string(),
3502            r#"object {foo: "bar", baz: "qux"}"#
3503        );
3504    }
3505
3506    #[test]
3507    fn map_display() {
3508        let ty = MapType::new(PrimitiveType::Integer, PrimitiveType::Boolean);
3509        let value: Value = Map::new(ty, [(1, true), (2, false)])
3510            .expect("should create map value")
3511            .into();
3512        assert_eq!(value.to_string(), "{1: true, 2: false}");
3513    }
3514
3515    #[test]
3516    fn pair_coercion() {
3517        let left = PrimitiveValue::new_file("foo");
3518        let right = PrimitiveValue::new_string("bar");
3519
3520        let ty = PairType::new(PrimitiveType::File, PrimitiveType::String);
3521        let value: Value = Pair::new(ty, left, right)
3522            .expect("should create map value")
3523            .into();
3524
3525        // Pair[File, String] -> Pair[String, File]
3526        let ty = PairType::new(PrimitiveType::String, PrimitiveType::File).into();
3527        let value = value.coerce(&ty).expect("value should coerce");
3528        assert_eq!(value.to_string(), r#"("foo", "bar")"#);
3529
3530        // Pair[String, File] -> Pair[Int, Int]
3531        let ty = PairType::new(PrimitiveType::Integer, PrimitiveType::Integer).into();
3532        assert_eq!(
3533            format!("{e:?}", e = value.coerce(&ty).unwrap_err()),
3534            r#"failed to coerce pair's left value
3535
3536Caused by:
3537    cannot coerce type `String` to type `Int`"#
3538        );
3539    }
3540
3541    #[test]
3542    fn pair_display() {
3543        let ty = PairType::new(PrimitiveType::Integer, PrimitiveType::Boolean);
3544        let value: Value = Pair::new(ty, 12345, false)
3545            .expect("should create pair value")
3546            .into();
3547        assert_eq!(value.to_string(), "(12345, false)");
3548    }
3549
3550    #[test]
3551    fn struct_coercion() {
3552        let ty = StructType::new(
3553            "Foo",
3554            [
3555                ("foo", PrimitiveType::Float),
3556                ("bar", PrimitiveType::Float),
3557                ("baz", PrimitiveType::Float),
3558            ],
3559        );
3560        let value: Value = Struct::new(ty, [("foo", 1.0), ("bar", 2.0), ("baz", 3.0)])
3561            .expect("should create map value")
3562            .into();
3563
3564        // Struct -> Map[String, Float]
3565        let ty = MapType::new(PrimitiveType::String, PrimitiveType::Float).into();
3566        let map_value = value.coerce(&ty).expect("value should coerce");
3567        assert_eq!(
3568            map_value.to_string(),
3569            r#"{"foo": 1.000000, "bar": 2.000000, "baz": 3.000000}"#
3570        );
3571
3572        // Struct -> Struct
3573        let ty = StructType::new(
3574            "Bar",
3575            [
3576                ("foo", PrimitiveType::Float),
3577                ("bar", PrimitiveType::Float),
3578                ("baz", PrimitiveType::Float),
3579            ],
3580        )
3581        .into();
3582        let struct_value = value.coerce(&ty).expect("value should coerce");
3583        assert_eq!(
3584            struct_value.to_string(),
3585            r#"Bar {foo: 1.000000, bar: 2.000000, baz: 3.000000}"#
3586        );
3587
3588        // Struct -> Object
3589        let object_value = value.coerce(&Type::Object).expect("value should coerce");
3590        assert_eq!(
3591            object_value.to_string(),
3592            r#"object {foo: 1.000000, bar: 2.000000, baz: 3.000000}"#
3593        );
3594    }
3595
3596    #[test]
3597    fn struct_display() {
3598        let ty = StructType::new(
3599            "Foo",
3600            [
3601                ("foo", PrimitiveType::Float),
3602                ("bar", PrimitiveType::String),
3603                ("baz", PrimitiveType::Integer),
3604            ],
3605        );
3606        let value: Value = Struct::new(
3607            ty,
3608            [
3609                ("foo", Value::from(1.101)),
3610                ("bar", PrimitiveValue::new_string("foo").into()),
3611                ("baz", 1234.into()),
3612            ],
3613        )
3614        .expect("should create map value")
3615        .into();
3616        assert_eq!(
3617            value.to_string(),
3618            r#"Foo {foo: 1.101000, bar: "foo", baz: 1234}"#
3619        );
3620    }
3621}