libcnb_data/
buildpack_plan.rs

1use serde::Deserialize;
2use toml::value::Table;
3
4#[derive(Debug, Deserialize)]
5#[serde(deny_unknown_fields)]
6pub struct BuildpackPlan {
7    #[serde(default)]
8    pub entries: Vec<Entry>,
9}
10
11#[derive(Debug, Deserialize)]
12#[serde(deny_unknown_fields)]
13pub struct Entry {
14    pub name: String,
15    #[serde(default)]
16    pub metadata: Table,
17}
18
19impl Entry {
20    /// Deserializes Metadata to a type T that implements Deserialize
21    ///
22    /// # Errors
23    /// This will return an error if it's not possible to serialize from a TOML Table into a T
24    pub fn metadata<'de, T>(&self) -> Result<T, toml::de::Error>
25    where
26        T: Deserialize<'de>,
27    {
28        // All toml `Value`s have `try_into()` which converts them to a `T` if `Deserialize` and
29        // `Deserializer` is implemented for `T`. Sadly, the `Table` type we use in `Entry` is not
30        // a `Value` so we need to make it one by wrapping it. We can't wrap directly in `Entry`
31        // since that would allow users to put non-table TOML values as metadata. As outlined
32        // earlier, we can't get around the clone since we're only borrowing the metadata.
33        toml::Value::Table(self.metadata.clone()).try_into()
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn it_parses_empty() {
43        let raw = "";
44
45        let result = toml::from_str::<BuildpackPlan>(raw);
46        assert!(result.is_ok());
47    }
48
49    #[test]
50    fn it_parses_simple() {
51        let toml = r#"
52[[entries]]
53name = "rust"
54"#;
55        let result = toml::from_str::<BuildpackPlan>(toml);
56        assert!(result.is_ok());
57    }
58
59    #[test]
60    fn it_parses_with_metadata() {
61        let toml = r#"
62[[entries]]
63name = "rust"
64    [entries.metadata]
65    version = "1.39"
66"#;
67
68        let result = toml::from_str::<BuildpackPlan>(toml);
69        assert!(result.is_ok());
70    }
71
72    #[test]
73    fn it_deserializes_metadata() {
74        #[derive(Deserialize, Eq, PartialEq, Debug)]
75        struct Metadata {
76            foo: String,
77        }
78
79        let mut metadata = Table::new();
80        metadata.insert(
81            String::from("foo"),
82            toml::Value::String(String::from("bar")),
83        );
84        let entry = Entry {
85            name: String::from("foo"),
86            metadata,
87        };
88
89        assert_eq!(
90            entry.metadata(),
91            Ok(Metadata {
92                foo: String::from("bar"),
93            })
94        );
95    }
96}