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 pkgs;
|
||||||
mod repos;
|
mod repos;
|
||||||
|
|
||||||
|
//
|
||||||
|
// ####### Repository stuff ##########
|
||||||
|
//
|
||||||
|
|
||||||
/// Use as #[::bok::repository(MyBaseRepo)]
|
/// Use as #[::bok::repository(MyBaseRepo)]
|
||||||
/// Will setup a `base` field that is the given base repo
|
/// Will setup a `base` field that is the given base repo
|
||||||
/// and add `#[derive(::bok::Repository)]`
|
/// and add `#[derive(::bok::Repository)]`
|
||||||
///
|
///
|
||||||
/// e.g.: `#[::bok::repository(::bok::RepositoryEmpty)]`
|
/// e.g.: `#[::bok::repository(::bok::RepositoryEmpty)]`
|
||||||
#[::macro_magic::import_tokens_attr]
|
#[::macro_magic::import_tokens_attr]
|
||||||
|
//#[with_custom_parsing(repos::BaseSet)]
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn repository(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn repository(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
crate::repos::repository(attrs, input)
|
crate::repos::repository(attrs, input)
|
||||||
@ -47,6 +52,25 @@ pub fn derive_repository(input: TokenStream) -> TokenStream {
|
|||||||
crate::repos::derive_repository(input)
|
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]`
|
/// Use on a function as `#[::bok::pkg_fn_to_code]`
|
||||||
/// will create a new function, same name with `_code` that
|
/// will create a new function, same name with `_code` that
|
||||||
/// returns the ::proc_macro2::TokenStream of the function
|
/// returns the ::proc_macro2::TokenStream of the function
|
||||||
|
@ -17,15 +17,80 @@
|
|||||||
|
|
||||||
use ::proc_macro::TokenStream;
|
use ::proc_macro::TokenStream;
|
||||||
use ::quote::quote;
|
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(
|
pub(crate) fn repository(
|
||||||
attrs: TokenStream,
|
attrs: TokenStream,
|
||||||
input: TokenStream,
|
input: TokenStream,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let base = parse_macro_input!(attrs as ItemStruct);
|
|
||||||
let local = parse_macro_input!(input as ItemStruct);
|
let local = parse_macro_input!(input as ItemStruct);
|
||||||
|
|
||||||
let Fields::Named(local_fields) = local.fields else {
|
let Fields::Named(local_fields) = local.fields else {
|
||||||
use ::syn::spanned::Spanned;
|
use ::syn::spanned::Spanned;
|
||||||
return ::syn::Error::new(
|
return ::syn::Error::new(
|
||||||
@ -36,7 +101,26 @@ pub(crate) fn repository(
|
|||||||
.into();
|
.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;
|
use ::syn::spanned::Spanned;
|
||||||
return ::syn::Error::new(
|
return ::syn::Error::new(
|
||||||
base.fields.span(),
|
base.fields.span(),
|
||||||
@ -45,22 +129,55 @@ pub(crate) fn repository(
|
|||||||
.to_compile_error()
|
.to_compile_error()
|
||||||
.into();
|
.into();
|
||||||
};
|
};
|
||||||
let local_fields_it = local_fields.named.iter();
|
// only add the base repo once
|
||||||
let base_fields_extra = base_fields.named.iter();
|
let mut base_empty_found = local_fields
|
||||||
let attrs = local.attrs;
|
.named
|
||||||
let generics = local.generics;
|
.iter()
|
||||||
let ident = local.ident;
|
.find(|&x| {
|
||||||
let vis = local.vis;
|
//
|
||||||
|
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! {
|
quote! {
|
||||||
#(#attrs)
|
#(#local_attrs)
|
||||||
*
|
*
|
||||||
#[::macro_magic::export_tokens]
|
#[::macro_magic::export_tokens]
|
||||||
#[derive(::bok::Repository, Debug)]
|
#[derive(::bok::Repository, Debug)]
|
||||||
#vis struct #ident<#generics> {
|
#vis struct #ident<#generics> {
|
||||||
#(#base_fields_extra),
|
#(#all_fields),
|
||||||
*
|
|
||||||
,
|
|
||||||
#(#local_fields_it),
|
|
||||||
*
|
*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,9 @@ use ::bok::repository;
|
|||||||
/// Base repository with some packages
|
/// Base repository with some packages
|
||||||
#[::bok::repository(::bok::RepositoryEmpty)]
|
#[::bok::repository(::bok::RepositoryEmpty)]
|
||||||
#[derive(::std::default::Default)]
|
#[derive(::std::default::Default)]
|
||||||
pub struct Pkgs1 {}
|
pub struct Pkgs1 {
|
||||||
|
r1: i32,
|
||||||
|
}
|
||||||
|
|
||||||
// Add some packages to the repository
|
// Add some packages to the repository
|
||||||
// all packages will have `::default()` values
|
// all packages will have `::default()` values
|
||||||
@ -46,11 +48,13 @@ bok::repo_packages! {
|
|||||||
/// This repository extends and changes Pkgs1
|
/// This repository extends and changes Pkgs1
|
||||||
#[::bok::repository(Pkgs1)]
|
#[::bok::repository(Pkgs1)]
|
||||||
#[derive(::std::default::Default)]
|
#[derive(::std::default::Default)]
|
||||||
pub struct Pkgs2 {}
|
pub struct Pkgs2 {
|
||||||
|
r2: i32,
|
||||||
|
}
|
||||||
|
|
||||||
// add a third package with `::default()` values
|
// add a third package with `::default()` values
|
||||||
bok::repo_packages! {
|
bok::repo_packages! {
|
||||||
Pkgs1 {
|
Pkgs2 {
|
||||||
Three,
|
Three,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,3 +72,8 @@ impl Pkgs2 {
|
|||||||
two.clone()
|
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};
|
pub use ::semver::{BuildMetadata, Prerelease, Version};
|
||||||
|
|
||||||
//use ::std::any::Any;
|
|
||||||
|
|
||||||
// Package stuff
|
// Package stuff
|
||||||
|
|
||||||
/// Get a package from its module and export it in the current module
|
/// 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]
|
#[::macro_magic::export_tokens]
|
||||||
#[derive(::std::default::Default, Debug)]
|
#[derive(::std::default::Default, Debug)]
|
||||||
pub struct RepositoryEmpty {
|
pub struct RepositoryEmpty {
|
||||||
test: i32,
|
// export_tokens needs something to export
|
||||||
|
bok_repo_empty_marker: ::std::marker::PhantomData<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Repository for RepositoryEmpty {
|
impl Repository for RepositoryEmpty {
|
||||||
fn name(&self) -> RepoName {
|
fn name(&self) -> RepoName {
|
||||||
"RepositoryEmpty".into()
|
"RepositoryEmpty".into()
|
||||||
|
Loading…
Reference in New Issue
Block a user