diff --git a/libcnb-data/src/buildpack.rs b/libcnb-data/src/buildpack.rs index c4afd14f..a719a4c0 100644 --- a/libcnb-data/src/buildpack.rs +++ b/libcnb-data/src/buildpack.rs @@ -178,6 +178,7 @@ impl Display for BuildpackApi { } libcnb_newtype!( + buildpack, /// Construct a [`BuildpackId`] value at compile time. /// /// Passing a string that is not a valid `BuildpackId` value will yield a compilation error. @@ -212,6 +213,7 @@ libcnb_newtype!( ); libcnb_newtype!( + buildpack, /// Construct a [`StackId`] value at compile time. /// /// Passing a string that is not a valid `StackId` value will yield a compilation error. diff --git a/libcnb-data/src/internals.rs b/libcnb-data/src/internals.rs new file mode 100644 index 00000000..78bfd635 --- /dev/null +++ b/libcnb-data/src/internals.rs @@ -0,0 +1,8 @@ +// This macro is used by all newtype literal macros to verify if the value matches the regex. It +// is not intended to be used outside of this crate. But since the code that macros expand to is +// just regular code, we need to expose this to users of this crate. +// +// We cannot use `::libcnb_proc_macros::verify_regex` in our macros directly as this would require +// every crate to explicitly import the `libcnb_proc_macros` crate as crates can't use code from +// transitive dependencies. +pub use libcnb_proc_macros::verify_regex; diff --git a/libcnb-data/src/launch.rs b/libcnb-data/src/launch.rs index 8de14004..137f1a6f 100644 --- a/libcnb-data/src/launch.rs +++ b/libcnb-data/src/launch.rs @@ -19,9 +19,11 @@ pub struct Launch { /// # Examples /// ``` /// use libcnb_data::launch; +/// use libcnb_data::process_type; +/// /// let mut launch_toml = launch::Launch::new(); -/// let web = launch::Process::new("web", "bundle", vec!["exec", "ruby", "app.rb"], -/// false, false).unwrap(); +/// let web = launch::Process::new(process_type!("web"), "bundle", vec!["exec", "ruby", "app.rb"], +/// false, false); /// /// launch_toml.processes.push(web); /// assert!(toml::to_string(&launch_toml).is_ok()); @@ -88,6 +90,7 @@ pub struct Slice { } libcnb_newtype!( + launch, /// Construct a [`ProcessType`] value at compile time. /// /// Passing a string that is not a valid `ProcessType` value will yield a compilation error. diff --git a/libcnb-data/src/lib.rs b/libcnb-data/src/lib.rs index 3086834e..25928e09 100644 --- a/libcnb-data/src/lib.rs +++ b/libcnb-data/src/lib.rs @@ -24,3 +24,7 @@ pub mod layer_content_metadata; pub mod store; mod newtypes; + +// Internals that need to be public for macros +#[doc(hidden)] +pub mod internals; diff --git a/libcnb-data/src/newtypes.rs b/libcnb-data/src/newtypes.rs index 28faaef3..02854676 100644 --- a/libcnb-data/src/newtypes.rs +++ b/libcnb-data/src/newtypes.rs @@ -24,6 +24,10 @@ use libcnb_proc_macros as _; /// # Usage: /// ``` /// libcnb_newtype!( +/// // The module of this crate that exports the newtype publicly. Since it might differ from +/// // the actual module structure, the macro needs a way to determine how to import the type +/// // from a user's buildpack crate. +/// tests::doctest /// /// RustDoc for the macro (optional) /// buildpack_id, /// /// RustDoc for the newtype itself (optional) @@ -43,6 +47,7 @@ use libcnb_proc_macros as _; /// ``` macro_rules! libcnb_newtype { ( + $path:path, $(#[$macro_attributes:meta])* $macro_name:ident, $(#[$type_attributes:meta])* @@ -117,10 +122,13 @@ macro_rules! libcnb_newtype { $(#[$macro_attributes])* macro_rules! $macro_name { ($value:expr) => { - ::libcnb_proc_macros::verify_regex!( + $crate::internals::verify_regex!( $regex, $value, - $value.parse::<$name>().unwrap(), + { + use $crate::$path as base; + $value.parse::().unwrap() + }, compile_error!(concat!( stringify!($value), " is not a valid ", @@ -140,6 +148,7 @@ mod test { use super::libcnb_newtype; libcnb_newtype!( + newtypes::test, capitalized_name, CapitalizedName, CapitalizedNameError, diff --git a/libcnb/examples/example-02-ruby-sample/src/main.rs b/libcnb/examples/example-02-ruby-sample/src/main.rs index 5b21bc66..0a4ecf00 100644 --- a/libcnb/examples/example-02-ruby-sample/src/main.rs +++ b/libcnb/examples/example-02-ruby-sample/src/main.rs @@ -2,7 +2,6 @@ use crate::layers::BundlerLayerLifecycle; use crate::layers::RubyLayerLifecycle; use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder}; use libcnb::buildpack_main; -use libcnb::data::launch::ProcessType; use libcnb::data::launch::{Launch, Process}; use libcnb::data::process_type; use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder}; diff --git a/libcnb/src/build.rs b/libcnb/src/build.rs index a8f59683..17514d52 100644 --- a/libcnb/src/build.rs +++ b/libcnb/src/build.rs @@ -52,12 +52,13 @@ pub(crate) enum InnerBuildResult { /// # Examples: /// ``` /// use libcnb::build::BuildResultBuilder; -/// use libcnb_data::launch::{Launch, Process}; +/// use libcnb::data::launch::{Launch, Process}; +/// use libcnb::data::process_type; /// /// let simple = BuildResultBuilder::new().build(); /// /// let with_launch = BuildResultBuilder::new() -/// .launch(Launch::new().process(Process::new("type", "command", vec!["-v"], false, false).unwrap())) +/// .launch(Launch::new().process(Process::new(process_type!("type"), "command", vec!["-v"], false, false))) /// .build(); /// ``` pub struct BuildResultBuilder {