/* * Copyright 2024 Luca Fulchir * * 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. */ use ::proc_macro::TokenStream; use ::quote::quote; use ::syn::parse_macro_input; pub(crate) fn collection( attrs: TokenStream, input: TokenStream, ) -> TokenStream { let ast = parse_macro_input!(input as ::syn::ItemStruct); if ast.ident.to_string() != "Collection" { use ::syn::spanned::Spanned; return ::syn::Error::new( ast.span(), "#[::bok_macro::collection(..)] should only be called on `struct \ Collection{}`", ) .to_compile_error() .into(); } use crate::PathList; let deps_list = parse_macro_input!(attrs as PathList); let mut all_deps_builder = deps_list.0.iter(); let name = all_deps_builder.next().expect( "`#[::bok_macro::collection(..)]` must have at least two arguments, \ the first is the repo path", ); let mut asdf = Vec::new(); for d in deps_list.0.iter() { let d_str = d .segments .iter() .fold(String::new(), |a, b| a + "_" + &b.ident.to_string()); asdf.push(::quote::format_ident!("{}", d_str)); } quote! { use ::bok_macro::collection_dep; #( const #asdf : u32 = 42; ) * #(#[::bok_macro::collection_dep(#all_deps_builder)]) * #[derive(::core::fmt::Debug)] pub struct Collection { repo: ::std::sync::Arc<#name>, pkgs: ::std::sync::RwLock< ::std::vec::Vec< ::std::sync::Arc< dyn ::bok::PkgBuilder>>>, } impl ::bok::Collection for Collection { fn as_any(&self) -> &dyn ::std::any::Any { self } fn as_any_mut(&mut self) -> &mut dyn ::std::any::Any { self } } } .into() } pub(crate) fn collection_dep( attrs: TokenStream, input: TokenStream, __source_path: TokenStream, ) -> TokenStream { let local = parse_macro_input!(input as ::syn::ItemStruct); let dep = parse_macro_input!(attrs as ::syn::ItemTrait); let local_ident = &local.ident; let dep_ident = parse_macro_input!(__source_path as ::syn::Path); let mut all_deps = Vec::with_capacity(dep.items.len()); for fn_it in dep.items.iter() { let ::syn::TraitItem::Fn(func) = fn_it else { continue; }; let sig = &func.sig; let pkgbuilder_name = &sig.ident; let builder: ::syn::ImplItemFn = ::syn::parse_quote! { #sig { ::std::boxed::Box::new( self.repo.#pkgbuilder_name() ) } }; all_deps.push(builder); } quote! { #local impl #dep_ident for #local_ident { #(#all_deps) * } } .into() }