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