Skip to content

Commit

Permalink
Merge pull request #382 from Malax/build-plan-refactor
Browse files Browse the repository at this point in the history
BuildPlan Metadata Support
  • Loading branch information
hone authored Mar 10, 2022
2 parents 55e7c52 + 18b93d1 commit 06b33cc
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 2 deletions.
2 changes: 2 additions & 0 deletions libcnb-data/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [Unreleased]
- Make `BuildPlan`'s `or` field public. ([#381](https://github.com/Malax/libcnb.rs/pull/381))
- Add way to construct `Require` with metadata field and integrate with `BuildPlanBuilder`. ([#382](https://github.com/Malax/libcnb.rs/pull/382))
- Add way to deserialize `Entry` metadata into a custom type. ([#382](https://github.com/Malax/libcnb.rs/pull/382))

## [0.5.0] 2022-02-28

Expand Down
46 changes: 44 additions & 2 deletions libcnb-data/src/build_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ impl BuildPlanBuilder {
self
}

pub fn requires(mut self, name: impl AsRef<str>) -> Self {
self.current_requires.push(Require::new(name.as_ref()));
pub fn requires(mut self, require: impl Into<Require>) -> Self {
self.current_requires.push(require.into());
self
}

Expand Down Expand Up @@ -105,6 +105,29 @@ impl Require {
metadata: Table::new(),
}
}

/// Convert a Serializable struct and store it as a toml Table for metadata
///
/// # Errors
/// This will return error for any normal TOML serialization error as well if it's not
/// possible to serialize as a TOML Table.
pub fn metadata<T: Serialize>(&mut self, metadata: T) -> Result<(), toml::ser::Error> {
if let toml::Value::Table(table) = toml::Value::try_from(metadata)? {
self.metadata = table;

Ok(())
} else {
Err(toml::ser::Error::Custom(String::from(
"Could not be serialized as a TOML Table.",
)))
}
}
}

impl<S: Into<String>> From<S> for Require {
fn from(s: S) -> Self {
Require::new(s)
}
}

#[cfg(test)]
Expand All @@ -119,4 +142,23 @@ mod tests {

assert!(toml::to_string(&build_plan).is_ok());
}

#[test]
fn it_serializes_metadata() {
#[derive(Serialize)]
struct Metadata {
foo: String,
}

let mut require = Require::new("foo");
let metadata = Metadata {
foo: String::from("bar"),
};
let result = require.metadata(metadata);
assert!(result.is_ok());
assert_eq!(
require.metadata.get("foo"),
Some(&toml::Value::String(String::from("bar")))
);
}
}
39 changes: 39 additions & 0 deletions libcnb-data/src/buildpack_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ pub struct Entry {
pub metadata: Table,
}

impl Entry {
/// Deserializes Metadata to a type T that implements Deserialize
///
/// # Errors
/// This will return an error if it's not possible to serialize from a TOML Table into a T
pub fn metadata<'de, T>(&self) -> Result<T, toml::de::Error>
where
T: Deserialize<'de>,
{
// All toml `Value`s have `try_into()` which converts them to a `T` if `Deserialize` and `Deserializer` is implemented for `T`. Sadly, the `Table` type we use in `Entry` is not a `Value` so we need to make it one by wrapping it. We cannot wrap directly in `Entry` since that would allow users to put non-table TOML values as metadata. As outlined earlier, we can't get around the clone since we're only borrowing the metadata.
toml::Value::Table(self.metadata.clone()).try_into()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -50,4 +64,29 @@ name = "rust"
let result = toml::from_str::<BuildpackPlan>(toml);
assert!(result.is_ok());
}

#[test]
fn it_deserializes_metadata() {
#[derive(Deserialize, Eq, PartialEq, Debug)]
struct Metadata {
foo: String,
}

let mut metadata = Table::new();
metadata.insert(
String::from("foo"),
toml::Value::String(String::from("bar")),
);
let entry = Entry {
name: String::from("foo"),
metadata,
};

assert_eq!(
entry.metadata(),
Ok(Metadata {
foo: String::from("bar"),
})
);
}
}

0 comments on commit 06b33cc

Please sign in to comment.