libcnb_data/
exec_d.rs

1use crate::newtypes::libcnb_newtype;
2use serde::Serialize;
3use std::collections::HashMap;
4
5/// Output of a CNB exec.d program.
6///
7/// See [Cloud Native Buildpack specification](https://github.com/buildpacks/spec/blob/main/buildpack.md#execd)
8#[derive(Serialize, Clone)]
9pub struct ExecDProgramOutput(HashMap<ExecDProgramOutputKey, String>);
10
11impl ExecDProgramOutput {
12    #[must_use]
13    pub fn new(map: HashMap<ExecDProgramOutputKey, String>) -> Self {
14        Self(map)
15    }
16}
17
18impl<K: Into<ExecDProgramOutputKey>, V: Into<String>, A: IntoIterator<Item = (K, V)>> From<A>
19    for ExecDProgramOutput
20{
21    fn from(a: A) -> Self {
22        Self(
23            a.into_iter()
24                .map(|(key, value)| (key.into(), value.into()))
25                .collect(),
26        )
27    }
28}
29
30libcnb_newtype!(
31    exec_d,
32    /// Construct a [`ExecDProgramOutputKey`] value at compile time.
33    ///
34    /// Passing a string that is not a valid `ExecDProgramOutputKey` value will yield a compilation
35    /// error.
36    ///
37    /// # Examples:
38    /// ```
39    /// use libcnb_data::exec_d::ExecDProgramOutputKey;
40    /// use libcnb_data::exec_d_program_output_key;
41    ///
42    /// let key: ExecDProgramOutputKey = exec_d_program_output_key!("PATH");
43    /// ```
44    exec_d_program_output_key,
45    /// A key of exec.d program output
46    ///
47    /// It MUST only contain numbers, letters, and the characters `_` and `-`.
48    ///
49    /// Use the [`exec_d_program_output_key`](crate::exec_d_program_output_key) macro to construct
50    /// a `ExecDProgramOutputKey` from a literal string. To parse a dynamic string into a
51    /// `ExecDProgramOutputKey`, use [`str::parse`](str::parse).
52    ///
53    /// # Examples
54    /// ```
55    /// use libcnb_data::exec_d::ExecDProgramOutputKey;
56    /// use libcnb_data::exec_d_program_output_key;
57    ///
58    /// let from_literal = exec_d_program_output_key!("ENV_VAR");
59    ///
60    /// let input = "ENV_VAR";
61    /// let from_dynamic: ExecDProgramOutputKey = input.parse().unwrap();
62    /// assert_eq!(from_dynamic, from_literal);
63    ///
64    /// let input = "!nv4lid";
65    /// let invalid: Result<ExecDProgramOutputKey, _> = input.parse();
66    /// assert!(invalid.is_err());
67    /// ```
68    ExecDProgramOutputKey,
69    ExecDProgramOutputKeyError,
70    r"^[A-Za-z0-9_-]+$"
71);
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn exec_d_program_output_key_validation_valid() {
79        assert!("FOO".parse::<ExecDProgramOutputKey>().is_ok());
80        assert!("foo".parse::<ExecDProgramOutputKey>().is_ok());
81        assert!("FOO_BAR".parse::<ExecDProgramOutputKey>().is_ok());
82        assert!("foo_bar".parse::<ExecDProgramOutputKey>().is_ok());
83        assert!("123".parse::<ExecDProgramOutputKey>().is_ok());
84        assert!("FOO-bar".parse::<ExecDProgramOutputKey>().is_ok());
85        assert!("foo-BAR".parse::<ExecDProgramOutputKey>().is_ok());
86    }
87
88    #[test]
89    fn exec_d_program_output_key_validation_invalid() {
90        assert_eq!(
91            "FOO BAR".parse::<ExecDProgramOutputKey>(),
92            Err(ExecDProgramOutputKeyError::InvalidValue(String::from(
93                "FOO BAR"
94            )))
95        );
96
97        assert_eq!(
98            "FOO.BAR".parse::<ExecDProgramOutputKey>(),
99            Err(ExecDProgramOutputKeyError::InvalidValue(String::from(
100                "FOO.BAR"
101            )))
102        );
103
104        assert_eq!(
105            "FOO/BAR".parse::<ExecDProgramOutputKey>(),
106            Err(ExecDProgramOutputKeyError::InvalidValue(String::from(
107                "FOO/BAR"
108            )))
109        );
110
111        assert_eq!(
112            "FÜCHSCHEN".parse::<ExecDProgramOutputKey>(),
113            Err(ExecDProgramOutputKeyError::InvalidValue(String::from(
114                "FÜCHSCHEN"
115            )))
116        );
117
118        assert_eq!(
119            "🦊".parse::<ExecDProgramOutputKey>(),
120            Err(ExecDProgramOutputKeyError::InvalidValue(String::from("🦊")))
121        );
122
123        assert_eq!(
124            "".parse::<ExecDProgramOutputKey>(),
125            Err(ExecDProgramOutputKeyError::InvalidValue(String::new()))
126        );
127    }
128}