Repo: packages in PhantomData
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
a5722bff5c
commit
f08ae227a2
23
Cargo.lock
generated
23
Cargo.lock
generated
@ -73,7 +73,6 @@ dependencies = [
|
||||
"bitflags",
|
||||
"bok-macro",
|
||||
"macro_magic",
|
||||
"paste",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"semver",
|
||||
@ -85,6 +84,7 @@ dependencies = [
|
||||
name = "bok-macro"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"macro_magic",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -180,6 +180,15 @@ dependencies = [
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.14"
|
||||
@ -328,12 +337,6 @@ version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.25"
|
||||
@ -442,6 +445,12 @@ version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.0"
|
||||
|
@ -13,7 +13,8 @@ categories = ["config"]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "2.0", features = ["full", "extra-traits"] }
|
||||
quote = { version = "1.0" }
|
||||
proc-macro2 = "1.0"
|
||||
convert_case = { version = "^0.6" }
|
||||
macro_magic = { version = "0.5", features = ["proc_support"] }
|
||||
proc-macro2 = "1.0"
|
||||
quote = { version = "1.0" }
|
||||
syn = { version = "2.0", features = ["full", "extra-traits"] }
|
||||
|
@ -56,16 +56,44 @@ pub fn derive_repository(input: TokenStream) -> TokenStream {
|
||||
/// Add multiple packages to a repo
|
||||
/// Usage:
|
||||
/// ```
|
||||
/// #[::bok::impl_repo(
|
||||
/// Mypkg1,
|
||||
/// Mypkg2,
|
||||
/// )]
|
||||
/// #[::bok::repo_packages(Mypkg1, Mypkg2)]
|
||||
/// struct MyRepo{}
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn repo_packages(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
crate::repos::repo_packages(attrs, input)
|
||||
}
|
||||
|
||||
/// Create the methods that will return the builders and packages
|
||||
///
|
||||
/// will actually merely rewrite the macro to get the actual Repo name
|
||||
/// in `#[::bok_macro::repo_impl_methods(MyRepo)]`
|
||||
///
|
||||
/// Usage:
|
||||
/// ```
|
||||
/// #[::bok::repo_impl]
|
||||
/// impl MyRepo{}
|
||||
/// ```
|
||||
//#[::macro_magic::import_tokens_attr]
|
||||
#[proc_macro_attribute]
|
||||
pub fn repo_impl(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
crate::repos::repo_impl(attrs, input)
|
||||
}
|
||||
|
||||
/// Internal. **Do not use unless you know what you are doing**
|
||||
/// Create the methods that will return the builders and packages
|
||||
/// Usage:
|
||||
/// ```
|
||||
/// #[::bok_macro::repo_impl(MyRepo)]
|
||||
/// 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)
|
||||
pub fn repo_impl_methods(
|
||||
attrs: TokenStream,
|
||||
input: TokenStream,
|
||||
) -> TokenStream {
|
||||
crate::repos::repo_impl_methods(attrs, input, __source_path)
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -17,75 +17,124 @@
|
||||
|
||||
use ::proc_macro::TokenStream;
|
||||
use ::quote::quote;
|
||||
use ::syn::{
|
||||
parse_macro_input, DeriveInput, Fields, Item, ItemImpl, ItemStruct,
|
||||
};
|
||||
use ::syn::{parse_macro_input, DeriveInput, Fields, ItemImpl, ItemStruct};
|
||||
|
||||
pub(crate) fn impl_repo(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let base = parse_macro_input!(attrs as ItemImpl);
|
||||
pub(crate) fn repo_impl(
|
||||
_attrs: TokenStream,
|
||||
input: TokenStream,
|
||||
) -> TokenStream {
|
||||
let local = parse_macro_input!(input as ItemImpl);
|
||||
|
||||
quote! {}.into()
|
||||
let reponame = &local.self_ty;
|
||||
|
||||
quote! {
|
||||
#[::bok_macro::repo_impl_methods(#reponame)]
|
||||
#local
|
||||
}
|
||||
.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)));
|
||||
|
||||
pub(crate) fn repo_impl_methods(
|
||||
attrs: TokenStream,
|
||||
input: TokenStream,
|
||||
__source_name: TokenStream,
|
||||
) -> TokenStream {
|
||||
let base = parse_macro_input!(attrs as ItemStruct);
|
||||
let local = parse_macro_input!(input as ItemImpl);
|
||||
let source_name = parse_macro_input!(__source_name as ::syn::Path);
|
||||
|
||||
if let ::syn::Type::Path(self_type_path) = local.self_ty.as_ref() {
|
||||
if self_type_path.path != source_name {
|
||||
return ::syn::Error::new(
|
||||
proc_macro2::Span::call_site(),
|
||||
"#[::bok_macro::repo_impl_methods(..)]: argument and impl \
|
||||
type differ",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
} else {
|
||||
return ::syn::Error::new(
|
||||
proc_macro2::Span::call_site(),
|
||||
"#[::bok_macro::repo_impl_methods(..)]: argument and impl type \
|
||||
differ",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
let local_attrs = local.attrs.iter();
|
||||
let generics = local.generics;
|
||||
let ident = &local.self_ty;
|
||||
let items = local.items.iter();
|
||||
|
||||
let ::syn::Fields::Named(base_fields) = base.fields else {
|
||||
return ::syn::Error::new(
|
||||
proc_macro2::Span::call_site(),
|
||||
"#[::bok_macro::repo_impl_methods(..)]: type has unsupported \
|
||||
unnamed fields",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
};
|
||||
|
||||
let mut fn_to_add = Vec::new();
|
||||
for f in base_fields.named.iter() {
|
||||
if !f
|
||||
.ident
|
||||
.as_ref()
|
||||
.is_some_and(|id| id.to_string().starts_with("_p_"))
|
||||
{
|
||||
continue;
|
||||
};
|
||||
let ::syn::Type::Path(f_type) = &f.ty else {
|
||||
continue;
|
||||
};
|
||||
let t_phantom = &f_type.path;
|
||||
let t_id = {
|
||||
let args = &t_phantom
|
||||
.segments
|
||||
.last()
|
||||
.expect("t_phantom no last?")
|
||||
.arguments;
|
||||
let ::syn::PathArguments::AngleBracketed(bracketed) = &args else {
|
||||
panic!("phantom without anglebracket?");
|
||||
};
|
||||
let ::syn::GenericArgument::Type(::syn::Type::Path(t)) =
|
||||
bracketed.args.first().expect("phantom bracketed, no args")
|
||||
else {
|
||||
panic!("phantom bracketed, generic not a type path");
|
||||
};
|
||||
t.path.clone()
|
||||
};
|
||||
let pkg_name = {
|
||||
let segment = t_id.segments.iter().last().unwrap();
|
||||
|
||||
&segment.ident
|
||||
};
|
||||
let pkg_fn: ::syn::ImplItemFn = ::syn::parse_quote! {
|
||||
pub fn #pkg_name(&self) -> #t_id {
|
||||
#t_id::default()
|
||||
}
|
||||
}
|
||||
|
||||
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()))
|
||||
};
|
||||
fn_to_add.push(pkg_fn);
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
let new_fn = fn_to_add.iter();
|
||||
|
||||
quote! {
|
||||
#(#local_attrs)
|
||||
*
|
||||
impl #ident<#generics> {
|
||||
#(#items)
|
||||
*
|
||||
#(#new_fn)
|
||||
*
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
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,
|
||||
@ -101,6 +150,7 @@ pub(crate) fn repository(
|
||||
.into();
|
||||
};
|
||||
|
||||
// do not duplicate token export or derive macro
|
||||
let local_attrs = local.attrs.iter().filter(|&x| {
|
||||
match &x.meta {
|
||||
::syn::Meta::Path(p) => {
|
||||
@ -145,57 +195,71 @@ pub(crate) fn repository(
|
||||
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(),
|
||||
"unnamed fields are not supported",
|
||||
"`#[::bok::repository(..)]`: base has unsupported unnamed fields",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
};
|
||||
// only add the base repo once
|
||||
let mut base_empty_found = local_fields
|
||||
// make sure base is a repo
|
||||
if base_fields
|
||||
.named
|
||||
.iter()
|
||||
.find(|&x| {
|
||||
let Some(id) = &x.ident else {
|
||||
return false;
|
||||
};
|
||||
id.to_string() == "bok_repo_empty_marker"
|
||||
x.ident
|
||||
.as_ref()
|
||||
.is_some_and(|id| id.to_string() == "_bok_repo")
|
||||
})
|
||||
.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);
|
||||
.is_none()
|
||||
{
|
||||
use ::syn::spanned::Spanned;
|
||||
return ::syn::Error::new(
|
||||
base.fields.span(),
|
||||
"`#[::bok::repository(..)]` base is not a repo",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
let mut all_fields = Vec::<::syn::Field>::with_capacity(
|
||||
local_fields.named.len() + base_fields.named.len(),
|
||||
);
|
||||
all_fields.extend(local_fields.named.iter().cloned());
|
||||
// make sure there is always `_bok_repo` marker
|
||||
if local_fields
|
||||
.named
|
||||
.iter()
|
||||
.find(|&f| {
|
||||
f.ident
|
||||
.as_ref()
|
||||
.is_some_and(|id| id.to_string() == "_bok_repo")
|
||||
})
|
||||
.is_none()
|
||||
{
|
||||
all_fields.push(::syn::parse_quote! {
|
||||
_bok_repo: ::std::marker::PhantomData<::bok::RepositoryEmpty>
|
||||
});
|
||||
}
|
||||
|
||||
for b_f in base_fields.named.iter() {
|
||||
let Some(b_f_id) = &b_f.ident else { continue };
|
||||
let b_f_id_str = b_f_id.to_string();
|
||||
if all_fields
|
||||
.iter()
|
||||
.find(|&f| {
|
||||
f.ident
|
||||
.as_ref()
|
||||
.is_some_and(|id| id.to_string() == b_f_id_str)
|
||||
})
|
||||
.is_none()
|
||||
{
|
||||
all_fields.push(b_f.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let mut all_fields = Vec::new();
|
||||
all_fields.extend(base_fields_extra.iter());
|
||||
all_fields.extend(local_fields.named.iter());
|
||||
quote! {
|
||||
#(#local_attrs)
|
||||
*
|
||||
@ -227,3 +291,182 @@ pub(crate) fn derive_repository(input: TokenStream) -> TokenStream {
|
||||
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
struct PathList(Vec<::syn::Path>);
|
||||
|
||||
impl ::syn::parse::Parse for PathList {
|
||||
fn parse(input: ::syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
use ::syn::punctuated::Punctuated;
|
||||
let raw =
|
||||
Punctuated::<::syn::Path, ::syn::Token![,]>::parse_terminated(
|
||||
input,
|
||||
)?;
|
||||
let mut result = Vec::with_capacity(raw.len());
|
||||
for r in raw.into_iter() {
|
||||
result.push(r)
|
||||
}
|
||||
Ok(PathList(result))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn repo_packages(
|
||||
attrs: TokenStream,
|
||||
input: TokenStream,
|
||||
) -> TokenStream {
|
||||
let local = parse_macro_input!(input as ItemStruct);
|
||||
let local_attrs = local.attrs.iter();
|
||||
let generics = local.generics;
|
||||
let ident = local.ident;
|
||||
let vis = local.vis;
|
||||
use ::syn::spanned::Spanned;
|
||||
let Fields::Named(ref local_fields) = local.fields else {
|
||||
use ::syn::spanned::Spanned;
|
||||
return ::syn::Error::new(
|
||||
local.fields.span(),
|
||||
"#[repo_packages(..)]: unnamed fields are not supported",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
};
|
||||
|
||||
// find the marker. we need it to separate things added manually
|
||||
// from things we get by extending the other repositories
|
||||
let Some(marker) = local_fields.named.iter().find(|&f| {
|
||||
f.ident
|
||||
.as_ref()
|
||||
.is_some_and(|id| id.to_string() == "_bok_repo")
|
||||
}) else {
|
||||
use ::syn::spanned::Spanned;
|
||||
return ::syn::Error::new(
|
||||
local_fields.span(),
|
||||
"#[repo_packages(..)]: struct is not a repository. Forgot \
|
||||
'#[::bok::repository(..)]` first?",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
};
|
||||
let fields_up_to_marker = local_fields
|
||||
.named
|
||||
.iter()
|
||||
.take_while(|&f| {
|
||||
f.ident
|
||||
.as_ref()
|
||||
.is_some_and(|id| id.to_string() != "_bok_repo")
|
||||
})
|
||||
.collect::<Vec<&::syn::Field>>();
|
||||
|
||||
let mut fields_after_marker = local_fields
|
||||
.named
|
||||
.iter()
|
||||
.skip_while(|&f| {
|
||||
f.ident
|
||||
.as_ref()
|
||||
.is_some_and(|id| id.to_string() != "_bok_repo")
|
||||
})
|
||||
.skip_while(|&f| {
|
||||
f.ident
|
||||
.as_ref()
|
||||
.is_some_and(|id| id.to_string() == "_bok_repo")
|
||||
})
|
||||
.collect::<Vec<&::syn::Field>>();
|
||||
|
||||
let packages = parse_macro_input!(attrs as PathList);
|
||||
|
||||
// the packages added manually must not be repeated manually.
|
||||
// but they will override any other package added by
|
||||
// extending the repository
|
||||
let mut fields_added = Vec::<::syn::Field>::with_capacity(packages.0.len());
|
||||
for p in packages.0 {
|
||||
let path_ident = &p.segments.last().unwrap().ident;
|
||||
|
||||
use ::convert_case::{Case, Casing};
|
||||
let pkg_id = "_p_".to_owned()
|
||||
+ path_ident.to_string().to_case(Case::Snake).as_str();
|
||||
|
||||
if fields_up_to_marker
|
||||
.iter()
|
||||
.find(|&f| {
|
||||
if let Some(id) = &f.ident {
|
||||
id.to_string() == pkg_id
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.is_some()
|
||||
{
|
||||
use ::syn::spanned::Spanned;
|
||||
return ::syn::Error::new(
|
||||
local_fields.span(),
|
||||
"#[repo_packages(..)]: package already present: ".to_owned()
|
||||
+ pkg_id.as_str(),
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
if fields_added
|
||||
.iter()
|
||||
.find(|&f| {
|
||||
if let Some(id) = &f.ident {
|
||||
id.to_string() == pkg_id
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.is_some()
|
||||
{
|
||||
use ::syn::spanned::Spanned;
|
||||
return ::syn::Error::new(
|
||||
local_fields.span(),
|
||||
"#[repo_packages(..)]: package added twice: ".to_owned()
|
||||
+ pkg_id.as_str(),
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
let pkg_ident =
|
||||
::quote::format_ident!("{}", pkg_id, span = local_fields.span());
|
||||
|
||||
let new_pkg: ::syn::Field = ::syn::parse_quote! {
|
||||
#pkg_ident : ::std::marker::PhantomData<#p>
|
||||
};
|
||||
|
||||
fields_added.push(new_pkg);
|
||||
fields_after_marker.retain(|&f| {
|
||||
f.ident.as_ref().is_some_and(|id| id.to_string() != pkg_id)
|
||||
});
|
||||
}
|
||||
|
||||
let mut all_fields =
|
||||
Vec::with_capacity(local_fields.named.len() + fields_added.len());
|
||||
all_fields.extend(fields_up_to_marker.iter());
|
||||
all_fields.extend(fields_added.iter());
|
||||
all_fields.push(marker);
|
||||
all_fields.extend(fields_after_marker.iter());
|
||||
|
||||
quote! {
|
||||
#(#local_attrs)
|
||||
*
|
||||
#vis struct #ident<#generics> {
|
||||
#(#all_fields),
|
||||
*
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
fn path_to_snake_case(path: &::syn::Path) -> String {
|
||||
let mut s = String::new();
|
||||
|
||||
let mut is_first = true;
|
||||
for segment in path.segments.iter() {
|
||||
if !is_first {
|
||||
s += "_";
|
||||
} else {
|
||||
is_first = false
|
||||
}
|
||||
s += segment.ident.to_string().as_str();
|
||||
}
|
||||
|
||||
use ::convert_case::{Case, Casing};
|
||||
|
||||
s.to_case(Case::Snake)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
mod conf;
|
||||
mod pkgs;
|
||||
mod repos;
|
||||
|
||||
/*
|
||||
trait TP {
|
||||
@ -37,10 +37,10 @@ impl TP for P {
|
||||
*/
|
||||
|
||||
fn main() {
|
||||
let one = pkgs::one::One::default();
|
||||
let one = repos::pkgs::one::One::default();
|
||||
|
||||
let pkgs1 = pkgs::Pkgs1::default();
|
||||
let pkgs2 = pkgs::Pkgs2::default();
|
||||
let pkgs1 = repos::Pkgs1::default();
|
||||
let pkgs2 = repos::Pkgs2::default();
|
||||
use ::bok::Repository;
|
||||
println!("pkgs1: {}", pkgs1.name());
|
||||
println!("pkgs2: {}", pkgs2.name());
|
||||
|
@ -19,43 +19,37 @@
|
||||
//! Example of two package repositories, where one
|
||||
//! extends ancd changes another
|
||||
|
||||
pub mod pkgs;
|
||||
|
||||
// FIXME: why?
|
||||
use ::bok_macro::repo_impl_methods;
|
||||
|
||||
// Export multiple packages in this module
|
||||
use ::bok::repository;
|
||||
::bok::moduse! {
|
||||
one,
|
||||
two,
|
||||
three,
|
||||
}
|
||||
|
||||
///
|
||||
/// Base repository with some packages
|
||||
#[::bok::repository(::bok::RepositoryEmpty)]
|
||||
#[::bok::repo_packages(pkgs::one::One)]
|
||||
#[derive(::std::default::Default)]
|
||||
pub struct Pkgs1 {
|
||||
r1: i32,
|
||||
}
|
||||
|
||||
// Add some packages to the repository
|
||||
// all packages will have `::default()` values
|
||||
bok::repo_packages! {
|
||||
Pkgs1 {
|
||||
One,
|
||||
}
|
||||
}
|
||||
#[::bok::repo_impl]
|
||||
impl Pkgs1 {}
|
||||
|
||||
///
|
||||
/// This repository extends and changes Pkgs1
|
||||
#[::bok::repository(Pkgs1)]
|
||||
#[::bok::repo_packages(pkgs::two::Two)]
|
||||
#[derive(::std::default::Default)]
|
||||
pub struct Pkgs2 {
|
||||
r2: i32,
|
||||
}
|
||||
|
||||
// add a third package with `::default()` values
|
||||
bok::repo_packages! {
|
||||
Pkgs2 {
|
||||
Three,
|
||||
}
|
||||
}
|
||||
#[::bok::repo_impl]
|
||||
impl Pkgs2 {}
|
||||
|
||||
/*
|
||||
impl Pkgs2 {
|
23
bok-utils/src/repos/pkgs/mod.rs
Normal file
23
bok-utils/src/repos/pkgs/mod.rs
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2024 Luca Fulchir <luca.fulchir@runesauth.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 with LLVM exception (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License and of the exception at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* https://spdx.org/licenses/LLVM-exception.html
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Export multiple packages in this module
|
||||
::bok::moduse! {
|
||||
one,
|
||||
two,
|
||||
three,
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
use ::bok::package;
|
||||
|
||||
/// Example package
|
||||
#[::bok::package(crate::pkgs::One)]
|
||||
#[::bok::package(super::one::One)]
|
||||
pub struct Two {
|
||||
pub my_attr2: u32,
|
||||
}
|
@ -17,7 +17,6 @@ publish = false
|
||||
bitflags = "2.4"
|
||||
bok-macro = { path="../bok-macro" }
|
||||
macro_magic = { version = "0.5" }
|
||||
paste = "1.0"
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
semver = { version = "1.0" }
|
||||
|
@ -27,7 +27,8 @@ pub mod deps {
|
||||
}
|
||||
|
||||
pub use ::bok_macro::{
|
||||
package, package_impl, pkg_fn_to_code, repository, Package, Repository,
|
||||
package, package_impl, pkg_fn_to_code, repo_impl, repo_packages,
|
||||
repository, Package, Repository,
|
||||
};
|
||||
pub use ::semver::{BuildMetadata, Prerelease, Version};
|
||||
|
||||
@ -44,46 +45,6 @@ macro_rules! moduse {
|
||||
)*
|
||||
};
|
||||
}
|
||||
// re-export `paste` crate for next macros
|
||||
pub use ::paste;
|
||||
|
||||
/// Add multipla packages to a repo
|
||||
/// e.g.:
|
||||
/// bok::repo_packages! {
|
||||
/// MyRepo {
|
||||
/// Mypkg1,
|
||||
/// Mypkg2,
|
||||
/// }
|
||||
/// }
|
||||
#[macro_export]
|
||||
macro_rules! repo_packages {
|
||||
( $repo:ident { $($name:ident,)*} ) => {
|
||||
impl $repo {
|
||||
$crate::packages!{$($name ,)*}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Add multipla packages to a repo Impl
|
||||
/// e.g.:
|
||||
/// impl MyRepo {
|
||||
/// bok::packages! {
|
||||
/// Mypkg1,
|
||||
/// Mypkg2,
|
||||
/// }
|
||||
/// }
|
||||
#[macro_export]
|
||||
macro_rules! packages {
|
||||
($($name:ident,)*) => {
|
||||
$crate::paste::paste! {
|
||||
$(
|
||||
pub fn [<$name:snake>] (&self) -> [<$name Builder>] {
|
||||
$name::builder()
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Marks your struct as a repository
|
||||
pub trait Repository: ::core::fmt::Debug {
|
||||
@ -95,8 +56,7 @@ pub trait Repository: ::core::fmt::Debug {
|
||||
#[::macro_magic::export_tokens]
|
||||
#[derive(::std::default::Default, Debug)]
|
||||
pub struct RepositoryEmpty {
|
||||
// export_tokens needs something to export
|
||||
bok_repo_empty_marker: ::std::marker::PhantomData<Self>,
|
||||
_bok_repo: ::std::marker::PhantomData<Self>,
|
||||
}
|
||||
|
||||
impl Repository for RepositoryEmpty {
|
||||
|
Loading…
Reference in New Issue
Block a user