Skip to main content

wdl_engine/
outputs.rs

1//! Implementation of workflow and task outputs.
2
3use std::cmp::Ordering;
4
5use indexmap::IndexMap;
6use serde::Serialize;
7
8use crate::Value;
9
10/// Represents outputs of a WDL workflow or task.
11#[derive(Default, Debug)]
12pub struct Outputs {
13    /// The name of the outputs.
14    ///
15    /// This may be set to the name of the call in a workflow or the task name
16    /// for a direct task execution.
17    name: Option<String>,
18    /// The map of output name to value.
19    values: IndexMap<String, Value>,
20}
21
22impl Outputs {
23    /// Sets the name of the outputs collection.
24    ///
25    /// Typically this is the name of the call in a workflow.
26    pub fn with_name(mut self, name: impl Into<String>) -> Self {
27        self.name = Some(name.into());
28        self
29    }
30
31    /// Iterates over the outputs in the collection.
32    pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> + use<'_> {
33        self.values.iter().map(|(k, v)| (k.as_str(), v))
34    }
35
36    /// Gets an output of the collection by name.
37    ///
38    /// Returns `None` if an output with the given name doesn't exist.
39    pub fn get(&self, name: &str) -> Option<&Value> {
40        self.values.get(name)
41    }
42
43    /// Sorts the outputs according to a callback.
44    pub(crate) fn sort_by(&mut self, mut cmp: impl FnMut(&str, &str) -> Ordering) {
45        // We can sort unstable as none of the keys are equivalent in ordering; thus the
46        // resulting sort is still considered to be stable
47        self.values.sort_unstable_by(move |a, _, b, _| {
48            let ordering = cmp(a, b);
49            assert!(ordering != Ordering::Equal);
50            ordering
51        });
52    }
53}
54
55impl Serialize for Outputs {
56    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
57    where
58        S: serde::Serializer,
59    {
60        use serde::ser::SerializeMap;
61
62        let mut s = serializer.serialize_map(Some(self.values.len()))?;
63        for (k, v) in &self.values {
64            let v = crate::ValueSerializer::new(None, v, true);
65            match &self.name {
66                Some(prefix) => s.serialize_entry(&format!("{prefix}.{k}"), &v)?,
67                None => s.serialize_entry(k, &v)?,
68            }
69        }
70
71        s.end()
72    }
73}
74
75impl FromIterator<(String, Value)> for Outputs {
76    fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
77        Self {
78            name: None,
79            values: iter.into_iter().collect(),
80        }
81    }
82}
83
84impl From<IndexMap<String, Value>> for Outputs {
85    fn from(values: IndexMap<String, Value>) -> Self {
86        Self { name: None, values }
87    }
88}