Pkg Options and their tracking in dependencies
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
c80cabe74e
commit
590fdbf25a
@ -190,19 +190,38 @@ pub fn package_path(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
crate::pkgs::package_path(attrs, input, __source_path)
|
||||
}
|
||||
|
||||
/// Specify one or more build-time dependencies
|
||||
/// Specify one or more dependencies
|
||||
///
|
||||
/// e.g:
|
||||
/// ```
|
||||
/// #[::bok::package(::bok::PkgEmpty)]
|
||||
/// #[::bok::deps_build(some::Package, other::Package)]
|
||||
/// #[::bok::deps(some::Package, other::Package)]
|
||||
/// pub struct MyPkg {}
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn deps_build(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
crate::pkgs::deps_build(attrs, input)
|
||||
pub fn deps(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
crate::pkgs::deps(attrs, input)
|
||||
}
|
||||
|
||||
/*
|
||||
/// attribute for package optional feature fields
|
||||
/// marks a struct field as a package option
|
||||
/// the PkgBuilder will create apposite get/set and traits for the options
|
||||
///
|
||||
/// e.g:
|
||||
/// ```
|
||||
/// #[::bok::package(::bok::PkgEmpty)]
|
||||
/// pub struct MyPkg {
|
||||
/// #[::bok::option]
|
||||
/// with_ssl: bool,
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn option(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
crate::pkgs::option(attrs, input)
|
||||
}
|
||||
*/
|
||||
|
||||
/// Use as #[::bok::package_impl]
|
||||
/// adds the right generics to the package.
|
||||
///
|
||||
@ -303,7 +322,7 @@ pub fn package_impl_builder(
|
||||
/// * Builder pattern to a package
|
||||
/// * getters/setters for all package fields
|
||||
/// * deref for package
|
||||
#[proc_macro_derive(Package)]
|
||||
#[proc_macro_derive(Package, attributes(option))]
|
||||
pub fn derive_package(input: TokenStream) -> TokenStream {
|
||||
crate::pkgs::derive_package(input)
|
||||
}
|
||||
|
@ -209,16 +209,13 @@ pub(crate) fn package_path(
|
||||
.into()
|
||||
}
|
||||
|
||||
pub(crate) fn deps_build(
|
||||
attrs: TokenStream,
|
||||
input: TokenStream,
|
||||
) -> TokenStream {
|
||||
pub(crate) fn deps(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let mut packages = parse_macro_input!(attrs as crate::PathList);
|
||||
let local = parse_macro_input!(input as ::syn::ItemStruct);
|
||||
|
||||
// make sure all the packages have generics, and if not add the repo as
|
||||
// generic aka: rewrite
|
||||
// "#[deps_build(my::pkg)]" -->> "#[deps_build(my::pkg<R>)])"
|
||||
// "#[deps(my::pkg)]" -->> "#[deps(my::pkg<R>)])"
|
||||
let mut rewrite = false;
|
||||
let repo_argument = {
|
||||
let generic_id: ::syn::Path = ::syn::parse_quote!(id<R>);
|
||||
@ -234,7 +231,7 @@ pub(crate) fn deps_build(
|
||||
if rewrite {
|
||||
let p_list = packages.0.into_iter();
|
||||
return quote! {
|
||||
#[::bok::deps_build(#(#p_list,)*)]
|
||||
#[::bok::deps(#(#p_list,)*)]
|
||||
#local
|
||||
}
|
||||
.into();
|
||||
@ -279,6 +276,21 @@ pub(crate) fn deps_build(
|
||||
)
|
||||
})
|
||||
.collect::<Vec<::syn::Ident>>();
|
||||
let deps_builders2 = deps_builders.clone();
|
||||
let deps_options = packages
|
||||
.0
|
||||
.iter()
|
||||
.map(|x| {
|
||||
let mut trait_option_path = x.clone();
|
||||
let last_segment = trait_option_path.segments.last_mut().unwrap();
|
||||
last_segment.ident =
|
||||
quote::format_ident!("BokOptions{}", last_segment.ident);
|
||||
last_segment.arguments = ::syn::PathArguments::None;
|
||||
trait_option_path
|
||||
})
|
||||
.collect::<Vec<::syn::Path>>();
|
||||
let deps_options2 = deps_options.clone();
|
||||
let deps_options3 = deps_options.clone();
|
||||
|
||||
quote! {
|
||||
#(#local_attrs)
|
||||
@ -291,10 +303,14 @@ pub(crate) fn deps_build(
|
||||
pub trait #pkg_trait: ::bok::Repository {
|
||||
#(fn #deps(&self) -> ::std::boxed::Box<dyn ::bok::Pkg>;)
|
||||
*
|
||||
#(fn #deps_builders(&self)
|
||||
-> ::std::boxed::Box<dyn #deps_options2>;)
|
||||
*
|
||||
}
|
||||
#[::macro_magic::export_tokens(#pkg_builder_trait)]
|
||||
pub trait #pkg_builder_trait {
|
||||
#(fn #deps_builders(&self) -> ::std::boxed::Box<dyn ::bok::PkgBuilder>;)
|
||||
#(fn #deps_builders2(&self)
|
||||
-> ::std::boxed::Box<dyn #deps_options3>;)
|
||||
*
|
||||
}
|
||||
}
|
||||
@ -584,6 +600,7 @@ pub(crate) fn package_impl_builder(
|
||||
let pkg_name = pkg.ident;
|
||||
let name_builder = ::quote::format_ident!("{}Builder", pkg_name);
|
||||
let trait_deps = ::quote::format_ident!("BokDeps{}", pkg_name);
|
||||
let trait_options = ::quote::format_ident!("BokOptions{}", pkg_name);
|
||||
let non_opt_fields = elements.named.iter().filter_map(|field| {
|
||||
if let Some(id) = field.ident.clone() {
|
||||
if id.to_string() == "version"
|
||||
@ -593,6 +610,14 @@ pub(crate) fn package_impl_builder(
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if field
|
||||
.attrs
|
||||
.iter()
|
||||
.find(|&a| a.path().is_ident("option"))
|
||||
.is_none()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
match &field.ty {
|
||||
syn::Type::Path(pth) => {
|
||||
let first_path = pth.path.segments.first().unwrap();
|
||||
@ -615,6 +640,14 @@ pub(crate) fn package_impl_builder(
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if field
|
||||
.attrs
|
||||
.iter()
|
||||
.find(|&a| a.path().is_ident("option"))
|
||||
.is_none()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
match &field.ty {
|
||||
syn::Type::Path(pth) => {
|
||||
let first_path = pth.path.segments.first().unwrap();
|
||||
@ -637,6 +670,14 @@ pub(crate) fn package_impl_builder(
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if field
|
||||
.attrs
|
||||
.iter()
|
||||
.find(|&a| a.path().is_ident("option"))
|
||||
.is_none()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
match &field.ty {
|
||||
syn::Type::Path(pth) => {
|
||||
let first_path = pth.path.segments.first().unwrap();
|
||||
@ -659,6 +700,14 @@ pub(crate) fn package_impl_builder(
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if field
|
||||
.attrs
|
||||
.iter()
|
||||
.find(|&a| a.path().is_ident("option"))
|
||||
.is_none()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
if let ::syn::Type::Path(pth) = &field.ty {
|
||||
let first_path = pth.path.segments.first().unwrap();
|
||||
if first_path.ident == "Option" {
|
||||
@ -680,15 +729,23 @@ pub(crate) fn package_impl_builder(
|
||||
});
|
||||
|
||||
let non_opt_types2 = non_opt_types.clone();
|
||||
let non_opt_types3 = non_opt_types.clone();
|
||||
let non_opt_types4 = non_opt_types.clone();
|
||||
let non_opt_fields2 = non_opt_fields.clone();
|
||||
let non_opt_fields3 = non_opt_fields.clone();
|
||||
let non_opt_fields4 = non_opt_fields.clone();
|
||||
let non_opt_fields5 = non_opt_fields.clone();
|
||||
let non_opt_fields6 = non_opt_fields.clone();
|
||||
let non_opt_fields7 = non_opt_fields.clone();
|
||||
let non_opt_fields8 = non_opt_fields.clone();
|
||||
let opt_fields2 = opt_fields.clone();
|
||||
let opt_fields3 = opt_fields.clone();
|
||||
let opt_fields4 = opt_fields.clone();
|
||||
let opt_fields5 = opt_fields.clone();
|
||||
let opt_fields6 = opt_fields.clone();
|
||||
let opt_types2 = opt_types.clone();
|
||||
let opt_types3 = opt_types.clone();
|
||||
let opt_types4 = opt_types.clone();
|
||||
let full_export_path_name = proc_macro2::Ident::new(
|
||||
&("_bok_pkgbuilder_".to_owned() + &pkg_name.to_string()),
|
||||
proc_macro2::Span::call_site(),
|
||||
@ -704,7 +761,7 @@ pub(crate) fn package_impl_builder(
|
||||
#(#non_opt_fields: ::std::option::Option<#non_opt_types>,)*
|
||||
#(#opt_fields: ::std::option::Option<#opt_types>,)*
|
||||
}
|
||||
//#[::macro_magic::export_tokens(#full_export_path_name)]
|
||||
#[::macro_magic::export_tokens(#full_export_path_name)]
|
||||
impl<R> ::bok::PkgBuilder for #name_builder<R>
|
||||
where
|
||||
R: ::bok::Repository + 'static + #trait_deps,
|
||||
@ -743,15 +800,12 @@ pub(crate) fn package_impl_builder(
|
||||
#(if self.#non_opt_fields2.is_none() {
|
||||
return ::std::result::Result::Err("unset field".into());
|
||||
})*
|
||||
Ok(
|
||||
Box::new(#pkg_name::<R> {
|
||||
_bok_base: ::std::marker::PhantomData::default(),
|
||||
_bok_repo: ::std::marker::PhantomData::default(),
|
||||
version: #pkg_name::<R>::default().version,
|
||||
#(#non_opt_fields3 : self.#non_opt_fields3.clone().unwrap(),)*
|
||||
#(#opt_fields2 : self.#opt_fields2.clone(),)*
|
||||
})
|
||||
)
|
||||
let mut pkg = ::std::boxed::Box::new(#pkg_name::<R>::default());
|
||||
#(pkg.#non_opt_fields3 = self.#non_opt_fields3.clone().unwrap();)
|
||||
*
|
||||
#(pkg.#opt_fields2 = self.#opt_fields2.clone();)
|
||||
*
|
||||
Ok(pkg)
|
||||
}
|
||||
#(#local_funcs)
|
||||
*
|
||||
@ -779,26 +833,55 @@ pub(crate) fn package_impl_builder(
|
||||
pub fn as_builder_mut(&mut self) -> &mut dyn ::bok::PkgBuilder {
|
||||
self
|
||||
}
|
||||
#(pub fn #non_opt_fields4 (&mut self, val : #non_opt_types2) -> &mut Self {
|
||||
#(pub fn #non_opt_fields4 (&mut self, val : #non_opt_types2)
|
||||
-> ::std::result::Result<&mut Self, ()> {
|
||||
if self.#non_opt_fields4 != None &&
|
||||
self.#non_opt_fields4 != Some(val) {
|
||||
panic!("Package \"{}\": mandatory attribute set multiple times: \"{}\"",
|
||||
::std::stringify!(#pkg_name),
|
||||
::std::stringify!(#non_opt_fields4));
|
||||
}
|
||||
// FIXME: 'val' validation
|
||||
self.#non_opt_fields4 = Some(val);
|
||||
self
|
||||
Ok(self)
|
||||
})
|
||||
*
|
||||
#(pub fn #opt_fields3 (&mut self, val : #opt_types2) -> &mut Self {
|
||||
#(pub fn #opt_fields3 (&mut self, val : #opt_types2)
|
||||
-> ::std::result::Result<&mut Self, ()> {
|
||||
if self.#opt_fields3 != None &&
|
||||
self.#opt_fields3 != Some(val) {
|
||||
panic!("Package \"{}\": optional attribute set multiple times: \"{}\"",
|
||||
::std::stringify!(#pkg_name),
|
||||
::std::stringify!(#opt_fields3));
|
||||
}
|
||||
// FIXME: 'val' validation
|
||||
self.#opt_fields3 = Some(val);
|
||||
self
|
||||
Ok(self)
|
||||
})
|
||||
*
|
||||
}
|
||||
pub trait #trait_options: ::bok::PkgBuilder {
|
||||
#(fn #non_opt_fields7 (&mut self, val : #non_opt_types3)
|
||||
-> ::std::result::Result<(),()>;)
|
||||
*
|
||||
#(fn #opt_fields5 (&mut self, val : #opt_types3)
|
||||
-> ::std::result::Result<(),()>;)
|
||||
*
|
||||
}
|
||||
impl<R> #trait_options for #name_builder<R>
|
||||
where
|
||||
R: ::bok::Repository +'static + #trait_deps,
|
||||
{
|
||||
#(fn #non_opt_fields8 (&mut self, val : #non_opt_types4)
|
||||
-> ::std::result::Result<(),()> {
|
||||
self.#non_opt_fields8(val)?;
|
||||
Ok(())
|
||||
})
|
||||
*
|
||||
#(fn #opt_fields6 (&mut self, val : #opt_types4)
|
||||
-> ::std::result::Result<(),()>{
|
||||
self.#opt_fields6(val)?
|
||||
Ok(())
|
||||
})
|
||||
*
|
||||
}
|
||||
@ -1007,6 +1090,14 @@ pub(crate) fn derive_package(input: TokenStream) -> TokenStream {
|
||||
&& id.to_string() != "_bok_base"
|
||||
&& id.to_string() != "_bok_repo"
|
||||
{
|
||||
if field
|
||||
.attrs
|
||||
.iter()
|
||||
.find(|&a| a.path().is_ident("option"))
|
||||
.is_none()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
return Some(&field.ident);
|
||||
}
|
||||
}
|
||||
|
@ -652,23 +652,24 @@ pub(crate) fn repo_impl_pkg_deps(
|
||||
let trait_deps = parse_macro_input!(attrs as ::syn::ItemTrait);
|
||||
let local = parse_macro_input!(input as ItemImpl);
|
||||
|
||||
let impl_trait = local
|
||||
let pkg_trait = local
|
||||
.trait_
|
||||
.expect("#[::bok_macro::repo_impl_pkg_deps()]: no trait found")
|
||||
.1;
|
||||
|
||||
let local_attrs = local.attrs.iter();
|
||||
let (_, generics, _) = local.generics.split_for_impl();
|
||||
let ident = &local.self_ty;
|
||||
|
||||
//let deps = Vec::<::syn::TraitItemFn>::new();
|
||||
let deps = trait_deps
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(|x| {
|
||||
if let ::syn::TraitItem::Fn(func) = &x {
|
||||
let name = &func.sig.ident;
|
||||
let output = &func.sig.output;
|
||||
let dep_impl: ::syn::TraitItemFn = ::syn::parse_quote! {
|
||||
fn #name(&self) -> ::std::boxed::Box<dyn ::bok::Pkg> {
|
||||
fn #name(&self) #output {
|
||||
::std::boxed::Box::new(self.#name())
|
||||
}
|
||||
};
|
||||
@ -682,7 +683,7 @@ pub(crate) fn repo_impl_pkg_deps(
|
||||
quote! {
|
||||
#(#local_attrs)
|
||||
*
|
||||
impl #impl_trait for #ident #generics {
|
||||
impl #pkg_trait for #ident #generics {
|
||||
#(#deps)
|
||||
*
|
||||
}
|
||||
|
@ -18,11 +18,14 @@
|
||||
/// Example package
|
||||
/// Automatically implements `.builder().my_attr(42).build()` pattern
|
||||
#[::bok::package(::bok::PkgEmpty)]
|
||||
#[::bok::deps_build()]
|
||||
#[::bok::deps()]
|
||||
pub struct One {
|
||||
pub my_attr: u32,
|
||||
#[option]
|
||||
my_attr: u32,
|
||||
}
|
||||
|
||||
// TODO: move this into the PkgBuilder
|
||||
// and have the package reference the builder
|
||||
#[::bok::package_impl]
|
||||
impl ::std::default::Default for One {
|
||||
fn default() -> Self {
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
/// Example package
|
||||
#[::bok::package(::bok::PkgEmpty)]
|
||||
#[::bok::deps_build(super::One)]
|
||||
#[::bok::deps(crate::repos::pkgs::One)]
|
||||
pub struct Three {
|
||||
pub my_attr: u32,
|
||||
}
|
||||
|
@ -16,10 +16,10 @@
|
||||
*/
|
||||
|
||||
/// Example package
|
||||
#[::bok::package(super::one::One)]
|
||||
#[::bok::deps_build(super::one::One)]
|
||||
#[::bok::package(crate::repos::pkgs::one::One)]
|
||||
#[::bok::deps(crate::repos::pkgs::one::One)]
|
||||
pub struct Two {
|
||||
pub my_attr2: u32,
|
||||
my_attr2: u32,
|
||||
}
|
||||
|
||||
#[::bok::package_impl]
|
||||
|
@ -28,8 +28,8 @@ pub mod deps {
|
||||
}
|
||||
|
||||
pub use ::bok_macro::{
|
||||
deps_build, package, package_impl, pkg_fn_to_code, repo_impl,
|
||||
repo_packages, repository, Package, Repository,
|
||||
deps, package, package_impl, pkg_fn_to_code, repo_impl, repo_packages,
|
||||
repository, Package, Repository,
|
||||
};
|
||||
pub use ::semver::{BuildMetadata, Prerelease, Version};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user