repo fields multiple extend
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
5d3fde9481
commit
9a83bf0dfa
@ -20,12 +20,17 @@ use ::proc_macro::TokenStream;
|
||||
mod pkgs;
|
||||
mod repos;
|
||||
|
||||
//
|
||||
// ####### Repository stuff ##########
|
||||
//
|
||||
|
||||
/// Use as #[::bok::repository(MyBaseRepo)]
|
||||
/// Will setup a `base` field that is the given base repo
|
||||
/// and add `#[derive(::bok::Repository)]`
|
||||
///
|
||||
/// e.g.: `#[::bok::repository(::bok::RepositoryEmpty)]`
|
||||
#[::macro_magic::import_tokens_attr]
|
||||
//#[with_custom_parsing(repos::BaseSet)]
|
||||
#[proc_macro_attribute]
|
||||
pub fn repository(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
crate::repos::repository(attrs, input)
|
||||
@ -47,6 +52,25 @@ pub fn derive_repository(input: TokenStream) -> TokenStream {
|
||||
crate::repos::derive_repository(input)
|
||||
}
|
||||
|
||||
/// Add multiple packages to a repo
|
||||
/// Usage:
|
||||
/// ```
|
||||
/// #[::bok::impl_repo(
|
||||
/// Mypkg1,
|
||||
/// Mypkg2,
|
||||
/// )]
|
||||
/// impl MyRepo{}
|
||||
/// ```
|
||||
#[::macro_magic::import_tokens_attr]
|
||||
#[proc_macro_attribute]
|
||||
pub fn impl_repository(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
crate::repos::impl_repo(attrs, input)
|
||||
}
|
||||
|
||||
//
|
||||
// ####### Package stuff ##########
|
||||
//
|
||||
|
||||
/// Use on a function as `#[::bok::pkg_fn_to_code]`
|
||||
/// will create a new function, same name with `_code` that
|
||||
/// returns the ::proc_macro2::TokenStream of the function
|
||||
|
@ -17,15 +17,80 @@
|
||||
|
||||
use ::proc_macro::TokenStream;
|
||||
use ::quote::quote;
|
||||
use ::syn::{parse_macro_input, DeriveInput, Fields, ItemStruct};
|
||||
use ::syn::{
|
||||
parse_macro_input, DeriveInput, Fields, Item, ItemImpl, ItemStruct,
|
||||
};
|
||||
|
||||
pub(crate) fn impl_repo(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let base = parse_macro_input!(attrs as ItemImpl);
|
||||
let local = parse_macro_input!(input as ItemImpl);
|
||||
|
||||
quote! {}.into()
|
||||
}
|
||||
/*
|
||||
// Either a series of paths, or a single one that we have to expand
|
||||
pub(crate) enum BaseSet {
|
||||
Paths(::std::vec::Vec<::syn::Path>),
|
||||
Single((::syn::Path, ItemStruct)),
|
||||
}
|
||||
impl ::syn::parse::Parse for BaseSet {
|
||||
fn parse(input: ::syn::parse::ParseStream) -> ::syn::parse::Result<Self> {
|
||||
if let Ok(path) = input.parse() {
|
||||
if let Ok(item_struct) = ItemStruct::parse(input) {
|
||||
return Ok(BaseSet::Single((path, item_struct)));
|
||||
}
|
||||
}
|
||||
|
||||
use ::syn::punctuated::Punctuated;
|
||||
let vars =
|
||||
Punctuated::<::syn::Path, ::syn::Token![,]>::parse_separated_nonempty(
|
||||
input,
|
||||
)?;
|
||||
if vars.len() >= 0 {
|
||||
return Err(::syn::parse::Error::new(input.span(), "GOT TWO"));
|
||||
}
|
||||
Ok(BaseSet::Paths(vars.into_iter().collect()))
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for BaseSet {
|
||||
fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
|
||||
match self {
|
||||
BaseSet::Paths(bases) => {
|
||||
for (i, base) in bases.iter().enumerate() {
|
||||
if i > 0 {
|
||||
tokens.extend(
|
||||
::proc_macro2::Punct::new(
|
||||
',',
|
||||
::proc_macro2::Spacing::Joint,
|
||||
)
|
||||
.into_token_stream(),
|
||||
);
|
||||
tokens.extend(base.to_token_stream());
|
||||
}
|
||||
base.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
BaseSet::Single((_, item_struct)) => item_struct.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::macro_magic::mm_core::ForeignPath for BaseSet {
|
||||
fn foreign_path(&self) -> &syn::Path {
|
||||
match self {
|
||||
BaseSet::Paths(bases) => &bases[0],
|
||||
BaseSet::Single((path, _)) => &path,
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub(crate) fn repository(
|
||||
attrs: TokenStream,
|
||||
input: TokenStream,
|
||||
) -> TokenStream {
|
||||
let base = parse_macro_input!(attrs as ItemStruct);
|
||||
let local = parse_macro_input!(input as ItemStruct);
|
||||
|
||||
let Fields::Named(local_fields) = local.fields else {
|
||||
use ::syn::spanned::Spanned;
|
||||
return ::syn::Error::new(
|
||||
@ -36,7 +101,26 @@ pub(crate) fn repository(
|
||||
.into();
|
||||
};
|
||||
|
||||
let Fields::Named(base_fields) = base.fields else {
|
||||
let local_attrs = local.attrs.iter().filter(|&x| {
|
||||
// don't export the same thing multiple times
|
||||
if let ::syn::Meta::Path(p) = &x.meta {
|
||||
if p.segments.len() == 2
|
||||
&& p.segments[0].ident == "macro_magic"
|
||||
&& p.segments[1].ident == "export_tokens"
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
true
|
||||
});
|
||||
let generics = local.generics;
|
||||
let ident = local.ident;
|
||||
let vis = local.vis;
|
||||
|
||||
let base = parse_macro_input!(attrs as ItemStruct);
|
||||
let mut base_fields_extra = Vec::new();
|
||||
let Fields::Named(base_fields) = &base.fields else {
|
||||
use ::syn::spanned::Spanned;
|
||||
return ::syn::Error::new(
|
||||
base.fields.span(),
|
||||
@ -45,22 +129,55 @@ pub(crate) fn repository(
|
||||
.to_compile_error()
|
||||
.into();
|
||||
};
|
||||
let local_fields_it = local_fields.named.iter();
|
||||
let base_fields_extra = base_fields.named.iter();
|
||||
let attrs = local.attrs;
|
||||
let generics = local.generics;
|
||||
let ident = local.ident;
|
||||
let vis = local.vis;
|
||||
// only add the base repo once
|
||||
let mut base_empty_found = local_fields
|
||||
.named
|
||||
.iter()
|
||||
.find(|&x| {
|
||||
//
|
||||
let Some(id) = &x.ident else {
|
||||
return false;
|
||||
};
|
||||
id.to_string() == "bok_repo_empty_marker"
|
||||
})
|
||||
.is_some();
|
||||
for f in base_fields.named.iter() {
|
||||
let Some(id) = &f.ident else { continue };
|
||||
if id.to_string() == "bok_repo_empty_marker" {
|
||||
if base_empty_found {
|
||||
continue;
|
||||
} else {
|
||||
base_empty_found = true;
|
||||
base_fields_extra.push(f);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if local_fields
|
||||
.named
|
||||
.iter()
|
||||
.find(|&x| {
|
||||
let Some(id_local) = &x.ident else {
|
||||
return false;
|
||||
};
|
||||
id_local.to_string() == id.to_string()
|
||||
})
|
||||
.is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
base_fields_extra.push(f);
|
||||
}
|
||||
|
||||
let mut all_fields = Vec::new();
|
||||
all_fields.extend(base_fields_extra.iter());
|
||||
all_fields.extend(local_fields.named.iter());
|
||||
quote! {
|
||||
#(#attrs)
|
||||
#(#local_attrs)
|
||||
*
|
||||
#[::macro_magic::export_tokens]
|
||||
#[derive(::bok::Repository, Debug)]
|
||||
#vis struct #ident<#generics> {
|
||||
#(#base_fields_extra),
|
||||
*
|
||||
,
|
||||
#(#local_fields_it),
|
||||
#(#all_fields),
|
||||
*
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,9 @@ use ::bok::repository;
|
||||
/// Base repository with some packages
|
||||
#[::bok::repository(::bok::RepositoryEmpty)]
|
||||
#[derive(::std::default::Default)]
|
||||
pub struct Pkgs1 {}
|
||||
pub struct Pkgs1 {
|
||||
r1: i32,
|
||||
}
|
||||
|
||||
// Add some packages to the repository
|
||||
// all packages will have `::default()` values
|
||||
@ -46,11 +48,13 @@ bok::repo_packages! {
|
||||
/// This repository extends and changes Pkgs1
|
||||
#[::bok::repository(Pkgs1)]
|
||||
#[derive(::std::default::Default)]
|
||||
pub struct Pkgs2 {}
|
||||
pub struct Pkgs2 {
|
||||
r2: i32,
|
||||
}
|
||||
|
||||
// add a third package with `::default()` values
|
||||
bok::repo_packages! {
|
||||
Pkgs1 {
|
||||
Pkgs2 {
|
||||
Three,
|
||||
}
|
||||
}
|
||||
@ -68,3 +72,8 @@ impl Pkgs2 {
|
||||
two.clone()
|
||||
}
|
||||
}
|
||||
/// This repository extends both Pkgs1 and Pkgs2
|
||||
#[::bok::repository(Pkgs1)]
|
||||
#[::bok::repository(Pkgs2)]
|
||||
#[derive(::std::default::Default)]
|
||||
pub struct Pkgs3 {}
|
||||
|
@ -32,8 +32,6 @@ pub use ::bok_macro::{
|
||||
};
|
||||
pub use ::semver::{BuildMetadata, Prerelease, Version};
|
||||
|
||||
//use ::std::any::Any;
|
||||
|
||||
// Package stuff
|
||||
|
||||
/// Get a package from its module and export it in the current module
|
||||
@ -98,8 +96,10 @@ pub trait Repository: ::core::fmt::Debug {
|
||||
#[::macro_magic::export_tokens]
|
||||
#[derive(::std::default::Default, Debug)]
|
||||
pub struct RepositoryEmpty {
|
||||
test: i32,
|
||||
// export_tokens needs something to export
|
||||
bok_repo_empty_marker: ::std::marker::PhantomData<Self>,
|
||||
}
|
||||
|
||||
impl Repository for RepositoryEmpty {
|
||||
fn name(&self) -> RepoName {
|
||||
"RepositoryEmpty".into()
|
||||
|
Loading…
Reference in New Issue
Block a user