repo: get list of pkgs and boxed pkg

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2024-11-30 13:41:21 +01:00
parent f08ae227a2
commit 631c3a19e5
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
2 changed files with 90 additions and 4 deletions

View File

@ -278,7 +278,72 @@ pub(crate) fn derive_repository(input: TokenStream) -> TokenStream {
let name = input.ident.clone();
let expanded = quote! {
let ::syn::Data::Struct(items) = &input.data else {
use ::syn::spanned::Spanned;
return ::syn::Error::new(
input.span(),
"#[derive(::bok::Repository)]: not called on a struct",
)
.to_compile_error()
.into();
};
if items
.fields
.iter()
.find(|&f| {
f.ident
.as_ref()
.is_some_and(|id| id.to_string() == "_bok_repo")
})
.is_none()
{
use ::syn::spanned::Spanned;
return ::syn::Error::new(
input.span(),
"#[derive(::bok::Repository)]: struct is not a bok repo. use \
`#[::bok::repository(..)]` first",
)
.to_compile_error()
.into();
}
// holds the list of all package names, snake case
let mut all_pkgs =
Vec::<(String, ::syn::Path)>::with_capacity(items.fields.len());
for it in items.fields.iter() {
let Some(id) = &it.ident else { continue };
let id_str = id.to_string();
if id_str.starts_with("_p_") {
let path = {
let ::syn::Type::Path(phantom_path) = &it.ty else {
continue;
};
let segment = phantom_path.path.segments.last().unwrap();
let ::syn::PathArguments::AngleBracketed(bracketed) =
&segment.arguments
else {
panic!("derive: phantom without anglebracket?");
};
let ::syn::GenericArgument::Type(::syn::Type::Path(t)) =
bracketed.args.first().expect("phantom bracketed, no args")
else {
panic!(
"derive: phantom bracketed, generic not a type path"
);
};
t.path.clone()
};
let name = id_str.strip_prefix("_p_").unwrap().to_owned();
all_pkgs.push((name, path));
}
}
all_pkgs.sort_by(|a, b| a.0.cmp(&b.0));
let pkgs_num: usize = all_pkgs.len();
let (pkg_names, pkg_types): (Vec<String>, Vec<::syn::Path>) =
all_pkgs.into_iter().map(|(a, b)| (a, b)).unzip();
quote! {
impl ::bok::Repository for #name {
fn name(&self) -> ::bok::RepoName {
(module_path!().to_owned() + "::" + ::std::stringify!(#name)).as_str().into()
@ -286,10 +351,22 @@ pub(crate) fn derive_repository(input: TokenStream) -> TokenStream {
fn path(&self) -> ::bok::Path<::bok::RepoName> {
(module_path!().to_owned() + "::" + ::std::stringify!(#name)).as_str().into()
}
fn pkg_list(&self) -> &[&'static str] {
const PKGS : [&'static str; #pkgs_num] = [
#(#pkg_names),
*
];
&PKGS
}
fn get(&self, pkg_name: &str) -> Option<::std::boxed::Box<dyn ::bok::Pkg>> {
match pkg_name {
#(#pkg_names => Some(::std::boxed::Box::new(#pkg_types::default())),)
*
_ => None,
}
}
}
};
TokenStream::from(expanded)
}.into()
}
struct PathList(Vec<::syn::Path>);

View File

@ -50,6 +50,8 @@ macro_rules! moduse {
pub trait Repository: ::core::fmt::Debug {
fn name(&self) -> RepoName;
fn path(&self) -> Path<RepoName>;
fn pkg_list(&self) -> &[&'static str];
fn get(&self, pkg_name: &str) -> Option<::std::boxed::Box<dyn Pkg>>;
}
/// This is an empty Package List.
@ -66,6 +68,13 @@ impl Repository for RepositoryEmpty {
fn path(&self) -> Path<RepoName> {
"::bok::RepositoryEmpty".into()
}
fn pkg_list(&self) -> &[&'static str] {
const PKGS: [&'static str; 0] = [];
&PKGS
}
fn get(&self, _pkg_name: &str) -> Option<::std::boxed::Box<dyn Pkg>> {
None
}
}
/// Print the code of the package