1extern crate proc_macro;
2
3mod types;
4
5use proc_macro::TokenStream;
6use quote::{format_ident, quote};
7use types::InjectionType;
8
9struct ComponentParams {
12 vis: syn::Visibility,
13 no_new: bool,
14}
15
16impl syn::parse::Parse for ComponentParams {
17 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
18 let mut params = ComponentParams {
19 vis: syn::Visibility::Inherited,
20 no_new: false,
21 };
22
23 while !input.is_empty() {
24 if input.peek(syn::Token![pub]) {
25 params.vis = input.parse()?;
26 } else {
27 let ident = input.parse::<syn::Ident>()?;
28 match ident.to_string().as_str() {
29 "no_new" => params.no_new = true,
30 s => {
31 return Err(syn::Error::new(
32 ident.span(),
33 format!("Unexpected parameter: {s}"),
34 ));
35 }
36 }
37 }
38
39 if !input.is_empty() {
40 input.parse::<syn::Token![,]>()?; }
42 }
43 Ok(params)
44 }
45}
46
47#[proc_macro_attribute]
50pub fn component(attr: TokenStream, item: TokenStream) -> TokenStream {
51 let params = syn::parse_macro_input!(attr as ComponentParams);
52
53 let ast: syn::Item = syn::parse(item).unwrap();
54 match ast {
55 syn::Item::Struct(struct_ast) => component_from_struct(params, struct_ast),
56 syn::Item::Impl(impl_ast) => component_from_impl(params, impl_ast),
57 _ => {
58 panic!("The #[component] macro can only be used on struct definition or an impl block")
59 }
60 }
61}
62
63#[proc_macro_attribute]
66pub fn scope(_args: TokenStream, item: TokenStream) -> TokenStream {
67 item
68}
69
70#[proc_macro_attribute]
73pub fn interface(_args: TokenStream, item: TokenStream) -> TokenStream {
74 item
75}
76
77#[proc_macro_attribute]
80pub fn meta(_args: TokenStream, item: TokenStream) -> TokenStream {
81 item
82}
83
84fn component_from_struct(params: ComponentParams, mut ast: syn::ItemStruct) -> TokenStream {
87 let impl_name = &ast.ident;
88 let impl_type = syn::parse2(quote! { #impl_name }).unwrap();
89 let impl_generics = syn::parse2(quote! {}).unwrap();
90
91 let args: Vec<_> = ast
92 .fields
93 .iter_mut()
94 .map(|f| {
95 (
96 f.ident.clone().unwrap(),
97 f.ty.clone(),
98 extract_attr_explicit(&mut f.attrs),
99 )
100 })
101 .collect();
102
103 let scope_type =
104 get_scope(&ast.attrs).unwrap_or_else(|| syn::parse_str("::dill::Transient").unwrap());
105
106 let interfaces = get_interfaces(&ast.attrs);
107 let meta = get_meta(&ast.attrs);
108
109 let mut stream: TokenStream = quote! { #ast }.into();
110
111 if !params.no_new {
112 stream.extend(implement_new(&impl_type, &args));
113 }
114
115 let builder: TokenStream = implement_builder(
116 &ast.vis,
117 &impl_type,
118 &impl_generics,
119 scope_type,
120 interfaces,
121 meta,
122 args,
123 !params.no_new,
124 );
125
126 stream.extend(builder);
127 stream
128}
129
130fn component_from_impl(params: ComponentParams, mut ast: syn::ItemImpl) -> TokenStream {
133 let impl_generics = &ast.generics;
134 let impl_type = &ast.self_ty;
135 let new = get_new(&mut ast.items).expect(
136 "When using #[component] macro on the impl block it's expected to contain a new() \
137 function. Otherwise use #[derive(Builder)] on the struct.",
138 );
139
140 let args: Vec<_> = new
141 .sig
142 .inputs
143 .iter_mut()
144 .map(|arg| match arg {
145 syn::FnArg::Typed(targ) => targ,
146 _ => panic!("Unexpected argument in new() function"),
147 })
148 .map(|arg| {
149 (
150 match arg.pat.as_ref() {
151 syn::Pat::Ident(ident) => ident.ident.clone(),
152 _ => panic!("Unexpected format of arguments in new() function"),
153 },
154 arg.ty.as_ref().clone(),
155 extract_attr_explicit(&mut arg.attrs),
156 )
157 })
158 .collect();
159
160 let scope_type =
161 get_scope(&ast.attrs).unwrap_or_else(|| syn::parse_str("::dill::Transient").unwrap());
162
163 let interfaces = get_interfaces(&ast.attrs);
164 let meta = get_meta(&ast.attrs);
165
166 let mut stream: TokenStream = quote! { #ast }.into();
167 let builder: TokenStream = implement_builder(
168 ¶ms.vis,
169 impl_type,
170 impl_generics,
171 scope_type,
172 interfaces,
173 meta,
174 args,
175 true,
176 );
177
178 stream.extend(builder);
179 stream
180}
181
182#[allow(clippy::too_many_arguments)]
185fn implement_new(impl_type: &syn::Type, args: &[(syn::Ident, syn::Type, bool)]) -> TokenStream {
186 let arg_decl = args.iter().map(|(name, ty, _)| quote! {#name: #ty});
187 let arg_name = args.iter().map(|(name, _, _)| name);
188
189 quote! {
190 impl #impl_type {
191 #[allow(clippy::too_many_arguments)]
192 pub fn new(
193 #(#arg_decl),*
194 ) -> Self {
195 Self {
196 #(#arg_name),*
197 }
198 }
199 }
200 }
201 .into()
202}
203
204#[allow(clippy::too_many_arguments)]
207fn implement_builder(
208 impl_vis: &syn::Visibility,
209 impl_type: &syn::Type,
210 _impl_generics: &syn::Generics,
211 scope_type: syn::Path,
212 interfaces: Vec<syn::Type>,
213 meta: Vec<syn::ExprStruct>,
214 args: Vec<(syn::Ident, syn::Type, bool)>,
215 has_new: bool,
216) -> TokenStream {
217 let builder_name = format_ident!("{}Builder", quote! { #impl_type }.to_string());
218
219 let arg_name: Vec<_> = args.iter().map(|(name, _, _)| name).collect();
220
221 let meta_provide: Vec<_> = meta
222 .iter()
223 .enumerate()
224 .map(|(i, e)| implement_meta_provide(i, e))
225 .collect();
226 let meta_vars: Vec<_> = meta
227 .iter()
228 .enumerate()
229 .map(|(i, e)| implement_meta_var(i, e))
230 .collect();
231
232 let mut arg_override_fn_field = Vec::new();
233 let mut arg_override_fn_field_ctor = Vec::new();
234 let mut arg_override_setters = Vec::new();
235 let mut arg_prepare_dependency = Vec::new();
236 let mut arg_provide_dependency = Vec::new();
237 let mut arg_dependency_info = Vec::new();
238
239 for (name, typ, is_explicit) in &args {
240 let (
241 override_fn_field,
242 override_fn_field_ctor,
243 override_setters,
244 prepare_dependency,
245 provide_dependency,
246 dependency_info,
247 ) = implement_arg(name, typ, &builder_name, &scope_type, *is_explicit);
248
249 arg_override_fn_field.push(override_fn_field);
250 arg_override_fn_field_ctor.push(override_fn_field_ctor);
251 arg_override_setters.push(override_setters);
252 arg_prepare_dependency.push(prepare_dependency);
253 arg_provide_dependency.push(provide_dependency);
254 arg_dependency_info.push(dependency_info);
255 }
256
257 arg_override_fn_field.retain(|t| !t.is_empty());
258 arg_override_fn_field_ctor.retain(|t| !t.is_empty());
259 arg_override_setters.retain(|t| !t.is_empty());
260 arg_prepare_dependency.retain(|t| !t.is_empty());
261 arg_provide_dependency.retain(|t| !t.is_empty());
262 arg_dependency_info.retain(|t| !t.is_empty());
263
264 let explicit_arg_decl: Vec<_> = args
265 .iter()
266 .filter(|(_, _, is_explicit)| *is_explicit)
267 .map(|(ident, ty, _)| quote! { #ident: #ty })
268 .collect();
269 let explicit_arg_provide: Vec<_> = args
270 .iter()
271 .filter(|(_, _, is_explicit)| *is_explicit)
272 .map(|(ident, _, _)| quote! { #ident })
273 .collect();
274
275 let ctor = if !has_new {
276 quote! {
277 #impl_type {
278 #( #arg_name: #arg_provide_dependency, )*
279 }
280 }
281 } else {
282 quote! {
283 #impl_type::new(#( #arg_provide_dependency, )*)
284 }
285 };
286
287 let component_or_explicit_factory = if explicit_arg_decl.is_empty() {
288 quote! {
289 impl ::dill::Component for #impl_type {
290 type Impl = #impl_type;
291 type Builder = #builder_name;
292
293 fn builder() -> Self::Builder {
294 #builder_name::new()
295 }
296 }
297 }
298 } else {
299 quote! {
300 impl #impl_type {
301 #[allow(clippy::too_many_arguments)]
302 pub fn builder(
303 #(#explicit_arg_decl),*
304 ) -> #builder_name {
305 #builder_name::new(
306 #(#explicit_arg_provide),*
307 )
308 }
309 }
310 }
311 };
312
313 let builder = quote! {
314 #impl_vis struct #builder_name {
315 dill_builder_scope: #scope_type,
316 #(#arg_override_fn_field),*
317 }
318
319 impl #builder_name {
320 #( #meta_vars )*
321
322 pub fn new(
323 #(#explicit_arg_decl),*
324 ) -> Self {
325 Self {
326 dill_builder_scope: #scope_type::new(),
327 #(#arg_override_fn_field_ctor),*
328 }
329 }
330
331 #( #arg_override_setters )*
332
333 fn build(&self, cat: &::dill::Catalog, ctx: &::dill::InjectionContext) -> Result<#impl_type, ::dill::InjectionError> {
334 let ctx_build = ctx.push_build(self);
335 let ctx = &ctx_build;
336
337 use ::dill::DependencySpec;
338 #( #arg_prepare_dependency )*
339 Ok(#ctor)
340 }
341 }
342
343 impl ::dill::Builder for #builder_name {
344 fn instance_type(&self) -> ::dill::TypeInfo {
345 ::dill::TypeInfo::of::<#impl_type>()
346 }
347
348 fn scope_type(&self) -> ::dill::TypeInfo {
349 ::dill::TypeInfo::of::<#scope_type>()
350 }
351
352 fn interfaces(&self, clb: &mut dyn FnMut(&::dill::TypeInfo) -> bool) {
353 #(
354 if !clb(&::dill::TypeInfo::of::<#interfaces>()) { return }
355 )*
356 }
357
358 fn dependencies(&self, clb: &mut dyn FnMut(&::dill::DependencyInfo) -> bool) {
359 #(
360 if !clb(& #arg_dependency_info) { return }
361 )*
362 }
363
364 fn metadata<'a>(&'a self, clb: & mut dyn FnMut(&'a dyn std::any::Any) -> bool) {
365 #( #meta_provide )*
366 }
367
368 fn get_any(&self, cat: &::dill::Catalog, ctx: &::dill::InjectionContext) -> Result<::std::sync::Arc<dyn ::std::any::Any + Send + Sync>, ::dill::InjectionError> {
369 Ok(::dill::TypedBuilder::get_with_context(self, cat, ctx)?)
370 }
371 }
372
373 impl ::dill::TypedBuilder<#impl_type> for #builder_name {
374 fn get_with_context(&self, cat: &::dill::Catalog, ctx: &::dill::InjectionContext) -> Result<std::sync::Arc<#impl_type>, ::dill::InjectionError> {
375 use ::dill::Scope;
376
377 let inst = self.dill_builder_scope.get_or_create(cat, || {
378 let inst = self.build(cat, ctx)?;
379 Ok(::std::sync::Arc::new(inst))
380 })?;
381
382 Ok(inst.downcast().unwrap())
383 }
384
385 fn bind_interfaces(&self, cat: &mut ::dill::CatalogBuilder) {
386 #(
387 cat.bind::<#interfaces, #impl_type>();
388 )*
389 }
390 }
391
392 #(
393 impl ::dill::TypedBuilderCast<#interfaces> for #builder_name
395 {
396 fn cast(self) -> impl ::dill::TypedBuilder<#interfaces> {
397 struct _B(#builder_name);
398
399 impl ::dill::Builder for _B {
400 fn instance_type(&self) -> ::dill::TypeInfo {
401 self.0.instance_type()
402 }
403 fn scope_type(&self) -> ::dill::TypeInfo {
404 self.0.scope_type()
405 }
406 fn interfaces(&self, clb: &mut dyn FnMut(&::dill::TypeInfo) -> bool) {
407 self.0.interfaces(clb)
408 }
409 fn dependencies(&self, clb: &mut dyn FnMut(&::dill::DependencyInfo) -> bool) {
410 self.0.dependencies(clb)
411 }
412 fn metadata<'a>(&'a self, clb: &mut dyn FnMut(&'a dyn std::any::Any) -> bool) {
413 self.0.metadata(clb)
414 }
415 fn get_any(&self, cat: &::dill::Catalog, ctx: &::dill::InjectionContext) -> Result<std::sync::Arc<dyn std::any::Any + Send + Sync>, ::dill::InjectionError> {
416 self.0.get_any(cat, ctx)
417 }
418 }
419
420 impl ::dill::TypedBuilder<#interfaces> for _B {
421 fn get_with_context(&self, cat: &::dill::Catalog, ctx: &::dill::InjectionContext) -> Result<::std::sync::Arc<#interfaces>, ::dill::InjectionError> {
422 match self.0.get_with_context(cat, ctx) {
423 Ok(v) => Ok(v),
424 Err(e) => Err(e),
425 }
426 }
427
428 fn bind_interfaces(&self, cat: &mut ::dill::CatalogBuilder) {
429 self.0.bind_interfaces(cat);
430 }
431 }
432
433 _B(self)
434 }
435 }
436 )*
437 };
438
439 quote! {
440 #component_or_explicit_factory
441
442 #builder
443 }
444 .into()
445}
446
447fn implement_arg(
450 name: &syn::Ident,
451 typ: &syn::Type,
452 builder: &syn::Ident,
453 scope_type: &syn::Path,
454 is_explicit: bool,
455) -> (
456 proc_macro2::TokenStream, proc_macro2::TokenStream, proc_macro2::TokenStream, proc_macro2::TokenStream, proc_macro2::TokenStream, proc_macro2::TokenStream, ) {
463 let override_fn_name = format_ident!("arg_{}_fn", name);
464
465 let injection_type = if is_explicit {
466 InjectionType::Value { typ: typ.clone() }
467 } else {
468 types::deduce_injection_type(typ)
469 };
470
471 let override_fn_field = if is_explicit {
474 quote! { #name: #typ }
475 } else {
476 match &injection_type {
477 InjectionType::Reference { .. }
478 | InjectionType::Catalog
479 | InjectionType::CatalogRef
480 | InjectionType::CatalogWeakRef => proc_macro2::TokenStream::new(),
481 _ => quote! {
482 #override_fn_name: Option<Box<dyn Fn(&::dill::Catalog) -> Result<#typ, ::dill::InjectionError> + Send + Sync>>
483 },
484 }
485 };
486
487 let override_fn_field_ctor = if is_explicit {
490 quote! { #name: #name }
491 } else {
492 match &injection_type {
493 InjectionType::Reference { .. }
494 | InjectionType::Catalog
495 | InjectionType::CatalogRef
496 | InjectionType::CatalogWeakRef => proc_macro2::TokenStream::new(),
497 _ => quote! { #override_fn_name: None },
498 }
499 };
500
501 let override_setters = if is_explicit {
503 proc_macro2::TokenStream::new()
504 } else {
505 match &injection_type {
506 InjectionType::Reference { .. }
507 | InjectionType::Catalog
508 | InjectionType::CatalogRef
509 | InjectionType::CatalogWeakRef => proc_macro2::TokenStream::new(),
510 _ => {
511 let setter_val_name = format_ident!("with_{}", name);
512 let setter_fn_name = format_ident!("with_{}_fn", name);
513 quote! {
514 pub fn #setter_val_name(mut self, val: #typ) -> #builder {
515 self.#override_fn_name = Some(Box::new(move |_| Ok(val.clone())));
516 self
517 }
518
519 pub fn #setter_fn_name(
520 mut self,
521 fun: impl Fn(&::dill::Catalog) -> Result<#typ, ::dill::InjectionError> + 'static + Send + Sync
522 ) -> #builder {
523 self.#override_fn_name = Some(Box::new(fun));
524 self
525 }
526 }
527 }
528 }
529 };
530
531 let prepare_dependency = if is_explicit {
533 proc_macro2::TokenStream::new()
534 } else {
535 let do_get_dependency = get_do_get_dependency(&injection_type, scope_type);
536 match &injection_type {
537 InjectionType::Reference { .. }
538 | InjectionType::Catalog
539 | InjectionType::CatalogRef
540 | InjectionType::CatalogWeakRef => {
541 quote! { let #name = #do_get_dependency; }
542 }
543 _ => quote! {
544 let #name = match &self.#override_fn_name {
545 Some(fun) => fun(cat)?,
546 _ => #do_get_dependency,
547 };
548 },
549 }
550 };
551
552 let provide_dependency = if is_explicit {
554 quote! { self.#name.clone() }
555 } else {
556 match &injection_type {
557 InjectionType::Reference { .. } => {
558 quote! { #name.as_ref() }
559 }
560 _ => quote! { #name },
561 }
562 };
563
564 let dependency_info = if is_explicit {
566 proc_macro2::TokenStream::new()
567 } else {
568 let info = get_do_get_dependency_info(&injection_type);
569 match &injection_type {
570 InjectionType::Reference { .. }
571 | InjectionType::Catalog
572 | InjectionType::CatalogRef
573 | InjectionType::CatalogWeakRef => info,
574 _ => quote! { #info.bound(self.#override_fn_name.is_some()) },
575 }
576 };
577
578 (
579 override_fn_field,
580 override_fn_field_ctor,
581 override_setters,
582 prepare_dependency,
583 provide_dependency,
584 dependency_info,
585 )
586}
587
588fn get_do_get_dependency(
591 injection_type: &InjectionType,
592 scope_type: &syn::Path,
593) -> proc_macro2::TokenStream {
594 match injection_type {
595 InjectionType::Catalog => {
596 if scope_type.segments.last().unwrap().ident != "Transient" {
597 panic!(
598 "`Catalog` can only be injected by value into components in a `Transient` \
599 scope as they guarantee a short lifetime. Injecting catalog into other \
600 scopes may result in cyclic references and resource leaks."
601 );
602 } else {
603 quote! { cat.clone() }
604 }
605 }
606 InjectionType::CatalogRef => quote! { cat },
607 InjectionType::CatalogWeakRef => quote! { cat.weak_ref() },
608 InjectionType::Arc { inner } => {
609 quote! { cat.get_with_context::<::dill::OneOf::<#inner>>(ctx)? }
610 }
611 InjectionType::Reference { inner } => {
612 quote! { cat.get_with_context::<::dill::OneOf::<#inner>>(ctx)? }
613 }
614 InjectionType::Option { element } => match element.as_ref() {
615 InjectionType::Arc { inner } => {
616 quote! { cat.get_with_context::<::dill::Maybe::<::dill::OneOf::<#inner>>>(ctx)? }
617 }
618 InjectionType::Value { typ } => {
619 quote! { cat.get_with_context::<::dill::Maybe::<::dill::OneOf::<#typ>>>(ctx)?.map(|v| v.as_ref().clone()) }
620 }
621 _ => {
622 unimplemented!("Currently only Option<Arc<Iface>> and Option<Value> are supported")
623 }
624 },
625 InjectionType::Lazy { element } => match element.as_ref() {
626 InjectionType::Arc { inner } => {
627 quote! { cat.get_with_context::<::dill::specs::Lazy::<::dill::OneOf::<#inner>>>(ctx)? }
628 }
629 _ => unimplemented!("Currently only Lazy<Arc<Iface>> is supported"),
630 },
631 InjectionType::Vec { item } => match item.as_ref() {
632 InjectionType::Arc { inner } => {
633 quote! { cat.get_with_context::<::dill::AllOf::<#inner>>(ctx)? }
634 }
635 _ => unimplemented!("Currently only Vec<Arc<Iface>> is supported"),
636 },
637 InjectionType::Value { typ } => {
638 quote! { cat.get_with_context::<::dill::OneOf::<#typ>>(ctx).map(|v| v.as_ref().clone())? }
639 }
640 }
641}
642
643fn get_do_get_dependency_info(injection_type: &InjectionType) -> proc_macro2::TokenStream {
644 match injection_type {
645 InjectionType::Catalog | InjectionType::CatalogRef => {
646 quote! { ::dill::DependencyInfo::of::<::dill::Catalog, ::dill::specs::OneOf::<::dill::Catalog>>() }
647 }
648 InjectionType::CatalogWeakRef => {
649 quote! { ::dill::DependencyInfo::of::<::dill::CatalogWeakRef, ::dill::specs::OneOf::<::dill::CatalogWeakRef>>() }
650 }
651 InjectionType::Arc { inner } => quote! {
652 ::dill::DependencyInfo::of::<#inner, ::dill::specs::OneOf::<#inner>>()
653 },
654 InjectionType::Reference { inner } => quote! {
655 ::dill::DependencyInfo::of::<#inner, ::dill::specs::OneOf::<#inner>>()
656 },
657 InjectionType::Option { element } => match element.as_ref() {
658 InjectionType::Arc { inner } => {
659 quote! {
660 ::dill::DependencyInfo::of::<#inner, ::dill::specs::Maybe::<::dill::OneOf::<#inner>>>()
661 }
662 }
663 InjectionType::Value { typ } => {
664 quote! {
665 ::dill::DependencyInfo::of::<#typ, ::dill::specs::Maybe::<::dill::OneOf::<#typ>>>()
666 }
667 }
668 _ => {
669 unimplemented!("Currently only Option<Arc<Iface>> and Option<Value> are supported")
670 }
671 },
672 InjectionType::Lazy { element } => match element.as_ref() {
673 InjectionType::Arc { inner } => {
674 quote! {
675 ::dill::DependencyInfo::of::<#inner, ::dill::specs::Lazy::<::dill::OneOf::<#inner>>>()
676 }
677 }
678 _ => unimplemented!("Currently only Lazy<Arc<Iface>> is supported"),
679 },
680 InjectionType::Vec { item } => match item.as_ref() {
681 InjectionType::Arc { inner } => quote! {
682 ::dill::DependencyInfo::of::<#inner, ::dill::specs::AllOf::<#inner>>()
683 },
684 _ => unimplemented!("Currently only Vec<Arc<Iface>> is supported"),
685 },
686 InjectionType::Value { typ } => {
687 quote! {
688 ::dill::DependencyInfo::of::<#typ, ::dill::specs::OneOf::<#typ>>()
689 }
690 }
691 }
692}
693
694fn implement_meta_var(index: usize, expr: &syn::ExprStruct) -> proc_macro2::TokenStream {
697 let ident = format_ident!("_meta_{index}");
698 let typ = &expr.path;
699 quote! {
700 const #ident: #typ = #expr;
701 }
702}
703
704fn implement_meta_provide(index: usize, _expr: &syn::ExprStruct) -> proc_macro2::TokenStream {
705 let ident = format_ident!("_meta_{index}");
706 quote! {
707 if !clb(&Self::#ident) { return }
708 }
709}
710
711fn get_scope(attrs: &Vec<syn::Attribute>) -> Option<syn::Path> {
715 let mut scope = None;
716
717 for attr in attrs {
718 if is_dill_attr(attr, "scope") {
719 attr.parse_nested_meta(|meta| {
720 scope = Some(meta.path);
721 Ok(())
722 })
723 .expect("Could not parse scope");
724 }
725 }
726
727 scope
728}
729
730fn get_interfaces(attrs: &Vec<syn::Attribute>) -> Vec<syn::Type> {
734 let mut interfaces = Vec::new();
735
736 for attr in attrs {
737 if is_dill_attr(attr, "interface") {
738 let iface = attr.parse_args().unwrap();
739 interfaces.push(iface);
740 }
741 }
742
743 interfaces
744}
745
746fn get_meta(attrs: &Vec<syn::Attribute>) -> Vec<syn::ExprStruct> {
750 let mut meta = Vec::new();
751
752 for attr in attrs {
753 if is_dill_attr(attr, "meta") {
754 let expr = attr.parse_args().unwrap();
755 meta.push(expr);
756 }
757 }
758
759 meta
760}
761
762fn is_dill_attr<I: ?Sized>(attr: &syn::Attribute, ident: &I) -> bool
765where
766 syn::Ident: PartialEq<I>,
767{
768 if attr.path().is_ident(ident) {
769 true
770 } else {
771 attr.path().segments.len() == 2
772 && &attr.path().segments[0].ident == "dill"
773 && attr.path().segments[1].ident == *ident
774 }
775}
776
777fn get_new(impl_items: &mut [syn::ImplItem]) -> Option<&mut syn::ImplItemFn> {
781 impl_items
782 .iter_mut()
783 .filter_map(|i| match i {
784 syn::ImplItem::Fn(m) => Some(m),
785 _ => None,
786 })
787 .find(|m| m.sig.ident == "new")
788}
789
790fn extract_attr_explicit(attrs: &mut Vec<syn::Attribute>) -> bool {
793 let mut present = false;
794 attrs.retain_mut(|attr| {
795 if is_attr_explicit(attr) {
796 present = true;
797 false
798 } else {
799 true
800 }
801 });
802 present
803}
804
805fn is_attr_explicit(attr: &syn::Attribute) -> bool {
806 if !is_dill_attr(attr, "component") {
807 return false;
808 }
809 let syn::Meta::List(meta) = &attr.meta else {
810 return false;
811 };
812 meta.tokens.to_string().contains("explicit")
813}