better ergonomics: hide generics in packages
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
34a1771695
commit
ae44556dd7
@ -150,10 +150,26 @@ pub fn pkg_fn_to_code(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
/// #[::bok::package(::bok::PkgEmpty)]
|
||||
/// pub struct MyPkg {}
|
||||
/// ```
|
||||
#[::macro_magic::import_tokens_attr]
|
||||
#[proc_macro_attribute]
|
||||
pub fn package(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
crate::pkgs::package(attrs, input, __source_path)
|
||||
crate::pkgs::package(attrs, input)
|
||||
}
|
||||
|
||||
/// **Internal**. try not to use
|
||||
/// Use as #[::bok::package(MyBasePackage<R>)]
|
||||
/// Will setup a `base` field that is the given base package
|
||||
/// and add `#[derive(::bok::Package)]`
|
||||
/// needs generics
|
||||
///
|
||||
/// e.g.:
|
||||
/// ```
|
||||
/// #[::bok::package_path(::base::pkg<R>)]
|
||||
/// pub struct MyPkg {}
|
||||
/// ```
|
||||
#[::macro_magic::import_tokens_attr]
|
||||
#[proc_macro_attribute]
|
||||
pub fn package_path(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
crate::pkgs::package_path(attrs, input, __source_path)
|
||||
}
|
||||
|
||||
/// Specify one or more build-time dependencies
|
||||
@ -170,12 +186,17 @@ pub fn deps_build(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
}
|
||||
|
||||
/// Use as #[::bok::package_impl]
|
||||
/// will add `#[::bok::package_impl_base(..)]` with proper arguments
|
||||
/// and export the resulting symbols
|
||||
/// adds the right generics to the package.
|
||||
///
|
||||
/// extra calls and changes are added to `::bok::Pkg` and ::std::Default traits
|
||||
///
|
||||
/// e.g.:
|
||||
/// ```
|
||||
/// #[::bok::package_impl]
|
||||
/// impl Default for Mypackage {
|
||||
/// fn default() -> Self { ... }
|
||||
/// }
|
||||
/// #[::bok::package_impl]
|
||||
/// impl ::bok::Pkg for MyPackage {
|
||||
/// fn build(&self) -> Result<(),()> {
|
||||
/// ...
|
||||
|
@ -43,7 +43,37 @@ pub(crate) fn pkg_fn_to_code(
|
||||
asdf.into()
|
||||
}
|
||||
|
||||
pub(crate) fn package(
|
||||
pub(crate) fn package(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let local = parse_macro_input!(input as ::syn::ItemStruct);
|
||||
let mut path = parse_macro_input!(attrs as ::syn::Path);
|
||||
|
||||
let last = path.segments.last().unwrap();
|
||||
if last.arguments.is_empty() {
|
||||
// make sure all the packages have generics, and if not add the
|
||||
// repo as generic aka: rewrite
|
||||
// "#[package(my::pkg)]" -->> "#[package(my::pkg<R>)])"
|
||||
// unless it's '::bok::PkgEmpty'
|
||||
if path.segments.len() != 2
|
||||
|| path.segments[0].ident.to_string() != "bok"
|
||||
|| path.segments[1].ident.to_string() != "PkgEmpty"
|
||||
{
|
||||
let repo_argument = {
|
||||
let generic_id: ::syn::Path = ::syn::parse_quote!(id<R>);
|
||||
generic_id.segments.last().unwrap().arguments.clone()
|
||||
};
|
||||
path.segments.last_mut().unwrap().arguments = repo_argument;
|
||||
}
|
||||
}
|
||||
|
||||
return quote! {
|
||||
use ::bok_macro::package_path;
|
||||
#[::bok_macro::package_path(#path)]
|
||||
#local
|
||||
}
|
||||
.into();
|
||||
}
|
||||
|
||||
pub(crate) fn package_path(
|
||||
attrs: TokenStream,
|
||||
input: TokenStream,
|
||||
__source_path: TokenStream,
|
||||
@ -183,9 +213,34 @@ pub(crate) fn deps_build(
|
||||
attrs: TokenStream,
|
||||
input: TokenStream,
|
||||
) -> TokenStream {
|
||||
let packages = parse_macro_input!(attrs as crate::PathList);
|
||||
|
||||
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>)])"
|
||||
let mut rewrite = false;
|
||||
let repo_argument = {
|
||||
let generic_id: ::syn::Path = ::syn::parse_quote!(id<R>);
|
||||
generic_id.segments.last().unwrap().arguments.clone()
|
||||
};
|
||||
for p in packages.0.iter_mut() {
|
||||
let last = p.segments.last_mut().unwrap();
|
||||
if last.arguments.is_empty() {
|
||||
rewrite = true;
|
||||
last.arguments = repo_argument.clone();
|
||||
}
|
||||
}
|
||||
if rewrite {
|
||||
let p_list = packages.0.into_iter();
|
||||
return quote! {
|
||||
#[::bok::deps_build(#(#p_list,)*)]
|
||||
#local
|
||||
}
|
||||
.into();
|
||||
}
|
||||
let packages = packages; // remove mut;
|
||||
|
||||
let ::syn::Fields::Named(local_fields) = local.fields else {
|
||||
use ::syn::spanned::Spanned;
|
||||
return ::syn::Error::new(
|
||||
@ -240,7 +295,32 @@ pub(crate) fn package_impl(
|
||||
_attrs: TokenStream,
|
||||
input: TokenStream,
|
||||
) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as ::syn::ItemImpl);
|
||||
let mut ast = parse_macro_input!(input as ::syn::ItemImpl);
|
||||
|
||||
if let Some((_, trait_name, _)) = &ast.trait_ {
|
||||
let s = &trait_name.segments;
|
||||
if s.len() != 2
|
||||
|| s[0].ident.to_string() != "bok"
|
||||
|| s[1].ident.to_string() != "Pkg"
|
||||
{
|
||||
//
|
||||
// only add the generic parameter and nothing else
|
||||
//
|
||||
let t_id = &ast.self_ty;
|
||||
let g: ::syn::ItemImpl = ::syn::parse_quote! {
|
||||
impl<R> trait_name for #t_id<R> where R: ::bok::Repository {}
|
||||
};
|
||||
ast.generics = g.generics;
|
||||
ast.self_ty = g.self_ty;
|
||||
// TODO: if the trait is `::std::default::Default`
|
||||
// then add the `_bok_base` and `_bok_repo` defaults automatically
|
||||
return quote! {
|
||||
#ast
|
||||
}
|
||||
.into();
|
||||
}
|
||||
}
|
||||
let ast = ast; // remove mut
|
||||
|
||||
let name_pkg = match &*ast.self_ty {
|
||||
::syn::Type::Path(tp) => match tp.path.get_ident() {
|
||||
|
@ -236,6 +236,33 @@ pub(crate) fn repo_packages(
|
||||
input: TokenStream,
|
||||
) -> TokenStream {
|
||||
let local = parse_macro_input!(input as ItemStruct);
|
||||
let mut packages = parse_macro_input!(attrs as crate::PathList);
|
||||
|
||||
// make sure all the packages have generics, and if not add the repo as
|
||||
// generic aka: rewrite
|
||||
// "#[repo_packages(my::pkg)]" -->> "#[repo_packages(my::pkg<Self>)])"
|
||||
let mut rewrite = false;
|
||||
let repo_argument = {
|
||||
let generic_id: ::syn::Path = ::syn::parse_quote!(id<Self>);
|
||||
generic_id.segments.last().unwrap().arguments.clone()
|
||||
};
|
||||
for p in packages.0.iter_mut() {
|
||||
let last = p.segments.last_mut().unwrap();
|
||||
if last.arguments.is_empty() {
|
||||
rewrite = true;
|
||||
last.arguments = repo_argument.clone();
|
||||
}
|
||||
}
|
||||
if rewrite {
|
||||
let p_list = packages.0.into_iter();
|
||||
return quote! {
|
||||
#[::bok::repo_packages(#(#p_list,)*)]
|
||||
#local
|
||||
}
|
||||
.into();
|
||||
}
|
||||
let packages = packages; // remove mut
|
||||
|
||||
let local_attrs = local.attrs.iter();
|
||||
let (_, generics, where_clause) = local.generics.split_for_impl();
|
||||
let ident = local.ident;
|
||||
@ -292,8 +319,6 @@ pub(crate) fn repo_packages(
|
||||
})
|
||||
.collect::<Vec<&::syn::Field>>();
|
||||
|
||||
let packages = parse_macro_input!(attrs as crate::PathList);
|
||||
|
||||
// the packages added manually must not be repeated manually.
|
||||
// but they will override any other package added by
|
||||
// extending the repository
|
||||
|
@ -30,7 +30,7 @@ use ::bok::repository;
|
||||
///
|
||||
/// Base repository with some packages
|
||||
#[::bok::repository(::bok::RepositoryEmpty)]
|
||||
#[::bok::repo_packages(pkgs::one::One<Self>)]
|
||||
#[::bok::repo_packages(pkgs::one::One)]
|
||||
#[derive(::std::default::Default)]
|
||||
pub struct Pkgs1 {
|
||||
r1: i32,
|
||||
@ -42,7 +42,7 @@ impl Pkgs1 {}
|
||||
///
|
||||
/// This repository extends and changes Pkgs1
|
||||
#[::bok::repository(Pkgs1)]
|
||||
#[::bok::repo_packages(pkgs::two::Two<Self>)]
|
||||
#[::bok::repo_packages(pkgs::two::Two)]
|
||||
#[derive(::std::default::Default)]
|
||||
pub struct Pkgs2 {
|
||||
r2: i32,
|
||||
|
@ -15,8 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use ::bok::package;
|
||||
|
||||
/// Example package
|
||||
/// Automatically implements `.builder().my_attr(42).build()` pattern
|
||||
#[::bok::package(::bok::PkgEmpty)]
|
||||
@ -25,10 +23,8 @@ pub struct One {
|
||||
pub my_attr: u32,
|
||||
}
|
||||
|
||||
impl<R> ::std::default::Default for One<R>
|
||||
where
|
||||
R: ::bok::Repository,
|
||||
{
|
||||
#[::bok::package_impl]
|
||||
impl ::std::default::Default for One {
|
||||
fn default() -> Self {
|
||||
One {
|
||||
_bok_base: ::std::marker::PhantomData::default(),
|
||||
|
@ -15,11 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use ::bok::package;
|
||||
|
||||
/// Example package
|
||||
#[::bok::package(::bok::PkgEmpty)]
|
||||
#[::bok::deps_build(super::One<R>)]
|
||||
#[::bok::deps_build(super::One)]
|
||||
pub struct Three {
|
||||
pub my_attr: u32,
|
||||
}
|
||||
|
@ -15,11 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use ::bok::package;
|
||||
|
||||
/// Example package
|
||||
#[::bok::package(super::one::One<R>)]
|
||||
#[::bok::deps_build(super::one::One<R>)]
|
||||
#[::bok::package(super::one::One)]
|
||||
#[::bok::deps_build(super::one::One)]
|
||||
pub struct Two {
|
||||
pub my_attr2: u32,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user