tola_caps_macros/lib.rs
1//! Procedural macros for tola-caps capability system
2//!
3//! # Unified Macro API
4//!
5//! ## Core Macros (Recommended)
6//!
7//! | Macro | Target | Purpose |
8//! |-------|--------|---------|
9//! | `#[cap]` | trait | Register trait for caps system |
10//! | `#[cap]` | struct/enum | Auto-detect std traits |
11//! | `#[specialize]` | impl | Attribute-style specialization |
12//! | `specialization!{}` | - | Block-style specialization |
13//! | `caps![]` | - | Build capability set type |
14//!
15//! ## Example
16//!
17//! ```ignore
18//! // 1. Define a trait with caps support
19//! #[cap]
20//! trait Serializable {
21//! fn serialize(&self) -> Vec<u8>;
22//! }
23//!
24//! // 2. Use in specialization
25//! specialization! {
26//! impl<T> Format for T {
27//! default fn format(&self) -> &'static str { "unknown" }
28//! }
29//! impl<T: Serializable> Format for T {
30//! fn format(&self) -> &'static str { "serializable" }
31//! }
32//! }
33//!
34//! // 3. Check at compile time
35//! if is_serializable::<MyType>() { ... }
36//! ```
37
38use proc_macro::TokenStream;
39use syn::parse_macro_input;
40
41// =============================================================================
42// Module Declarations (Three-tier: inner / common / user)
43// =============================================================================
44
45mod inner;
46mod common;
47mod user;
48
49// =============================================================================
50// Internal Macros (inner/)
51// =============================================================================
52
53/// Generate Peano number type aliases D0..Dn.
54///
55/// # Usage
56/// ```ignore
57/// peano!(64); // Generates D0 = Z, D1 = S<D0>, ..., D64 = S<D63>
58/// ```
59#[proc_macro]
60pub fn peano(input: TokenStream) -> TokenStream {
61 let input = parse_macro_input!(input as inner::peano::PeanoInput);
62 inner::peano::expand_peano(input).into()
63}
64
65/// Generate HashStream impl for ByteStream128.
66///
67/// ByteStream128 stores 64 nibbles as const generic params.
68/// This generates the impl that extracts Head (first nibble) and
69/// creates Tail (rotated version of the params).
70#[proc_macro]
71pub fn impl_byte_stream_128(_input: TokenStream) -> TokenStream {
72 inner::byte_stream::expand_impl_byte_stream_128().into()
73}
74
75/// Expand to: N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, NA, NB, NC, ND, NE, NF
76///
77/// Use in generic parameters or tuple fields.
78#[proc_macro]
79pub fn node16_slots(_input: TokenStream) -> TokenStream {
80 inner::node16::expand_slots().into()
81}
82
83/// Expand to: Node16<N0, N1, N2, ..., NF>
84///
85/// Use in impl blocks and type positions.
86#[proc_macro]
87pub fn node16_type(_input: TokenStream) -> TokenStream {
88 inner::node16::expand_node16_type().into()
89}
90
91/// Generate all std trait detection infrastructure.
92///
93/// This generates:
94/// - Capability markers (IsClone, IsCopy, etc.) with hash-based streams
95/// - Fallback traits (CloneFallback, etc.)
96/// - Select traits (SelectClone, etc.)
97/// - AutoCaps trait with all IS_XXX consts
98#[proc_macro]
99pub fn define_std_traits(_input: TokenStream) -> TokenStream {
100 inner::std_traits::expand_std_traits().into()
101}
102
103/// Generate the impl_auto_caps! macro.
104#[proc_macro]
105pub fn define_impl_auto_caps_macro(_input: TokenStream) -> TokenStream {
106 inner::std_traits::expand_impl_auto_caps_macro().into()
107}
108
109/// Generate the impl_std_types! macro for primitives and core types.
110#[proc_macro]
111pub fn define_impl_std_types_macro(_input: TokenStream) -> TokenStream {
112 inner::std_types::expand_impl_std_types_macro().into()
113}
114
115#[proc_macro]
116pub fn define_impl_std_lib_types_macro(_input: TokenStream) -> TokenStream {
117 inner::std_types::expand_impl_std_lib_types_macro().into()
118}
119
120/// Generate the impl_alloc_types! macro for alloc types.
121#[proc_macro]
122pub fn define_impl_alloc_types_macro(_input: TokenStream) -> TokenStream {
123 inner::std_types::expand_impl_alloc_types_macro().into()
124}
125
126
127/// Internal: Convert a path string to a Finger Tree identity type.
128/// Used by #[derive(Capability)] to create stable, reproducible identities.
129/// The input must be: concat!(module_path!(), "::", stringify!(TypeName))
130#[proc_macro]
131pub fn __internal_make_identity(input: TokenStream) -> TokenStream {
132 let _input_str = input.to_string();
133 user::capability::expand_make_identity(input.into()).into()
134}
135
136/// Internal: Generate IdentityBytes type from module path string.
137/// Uses const fn pack_str_bytes for const evaluation after concat!() expansion.
138#[proc_macro]
139pub fn make_identity_bytes(input: TokenStream) -> TokenStream {
140 user::capability::expand_make_identity_bytes(input.into()).into()
141}
142
143
144
145/// Generate a type-level nibble stream from an identifier name.
146///
147/// Usage: `name_stream!(MyStruct)` expands to `Cons<X4, Cons<...> ...>`
148#[proc_macro]
149pub fn name_stream(input: TokenStream) -> TokenStream {
150 let input = parse_macro_input!(input as inner::name_stream::NameStreamInput);
151 inner::name_stream::expand_name_stream(input).into()
152}
153
154/// Internal: Compute routing hash stream from a full module path string.
155/// Input must be a string literal (e.g. from `concat!`).
156#[proc_macro]
157pub fn make_routing_stream(input: TokenStream) -> TokenStream {
158 // Just delegates to the same logic as identity, but returns Stream type tokens
159 user::capability::expand_make_routing_stream(input.into()).into()
160}
161
162/// Implement `AutoCaps` and `AutoCapSet` for a type.
163///
164/// # Usage
165/// ```ignore
166/// impl_auto_caps!(MyType);
167/// ```
168#[proc_macro]
169pub fn impl_auto_caps(input: TokenStream) -> TokenStream {
170 inner::std_traits::expand_impl_auto_caps(input.into()).into()
171}
172
173/// Attribute macro for Node16 struct and impl blocks.
174///
175/// # Modes
176///
177/// - `#[node16]` - Basic placeholder replacement
178/// - `#[node16(each_slot)]` - Per-slot expansion with `_Slot_` and `each(_Slots_)`
179/// - `#[node16(for_nibble)]` - Generate 16 impls, one per nibble/slot pair
180/// - `#[node16(all_empty)]` - Generate empty Node16 type alias
181///
182/// # Placeholders
183///
184/// - `_Slots_` expands to N0, N1, ..., NF
185/// - `_Node16_` expands to Node16<N0, N1, ..., NF>
186/// - `each(_Slots_): Bound` expands to N0: Bound, ..., NF: Bound (each_slot mode)
187/// - `_Slot_` in statements: repeated 16 times (each_slot mode)
188/// - `_Nibble_` expands to X0, X1, ..., XF (for_nibble mode)
189/// - `_SlotN_` expands to N0, N1, ..., NF (for_nibble mode, paired with _Nibble_)
190///
191/// # Examples
192///
193/// ```ignore
194/// // Basic: struct and impl
195/// #[macros::node16]
196/// pub struct Node16<_Slots_>(PhantomData<(_Slots_,)>);
197///
198/// // Per-nibble impl (generates 16 impls)
199/// #[macros::node16(for_nibble)]
200/// impl<Cap, Depth, _Slots_> RouteQuery<Cap, Depth, _Nibble_> for _Node16_
201/// where _SlotN_: EvalAt<Has<Cap>, S<Depth>>
202/// {
203/// type Out = <_SlotN_ as EvalAt<Has<Cap>, S<Depth>>>::Out;
204/// }
205/// ```
206#[proc_macro_attribute]
207pub fn node16(attr: TokenStream, item: TokenStream) -> TokenStream {
208 let attr2: proc_macro2::TokenStream = attr.into();
209 let item2: proc_macro2::TokenStream = item.into();
210 let mode = inner::node16::parse_mode(attr2);
211 inner::node16::expand_trie16_with_mode(mode, item2).into()
212}
213
214/// Generate all 65536 ByteEq impls for type-level byte comparison.
215#[proc_macro]
216pub fn impl_byte_eq(_input: TokenStream) -> TokenStream {
217 inner::byte_eq::expand_byte_eq_impls().into()
218}
219
220// =============================================================================
221// User-facing Macros (user/)
222// =============================================================================
223
224/// Unified capability constraint macro with boolean expression support.
225///
226/// # Usage
227///
228/// ```ignore
229/// // Simple requirement
230/// #[caps_bound(CanRead)]
231/// fn read_doc<C>(doc: Doc<C>) { ... }
232///
233/// // Boolean logic
234/// #[caps_bound(requires = CanRead & (CanWrite | CanAdmin), conflicts = CanGuest)]
235/// fn secure_op<C>(doc: Doc<C>) { ... }
236///
237/// // Transparent mode (auto-inject generic)
238/// #[caps_bound(CanRead, transparent)]
239/// fn simple_read(doc: Doc) { ... }
240/// ```
241#[proc_macro_attribute]
242pub fn caps_bound(attr: TokenStream, item: TokenStream) -> TokenStream {
243 let args = parse_macro_input!(attr as user::CapsArgs);
244
245 let item_clone = item.clone();
246 if let Ok(func) = syn::parse::<syn::ItemFn>(item_clone.clone()) {
247 return user::expand_caps_fn(args, func);
248 }
249
250 let item_clone = item.clone();
251 if let Ok(item_struct) = syn::parse::<syn::ItemStruct>(item_clone.clone()) {
252 return user::expand_caps_struct(args, item_struct);
253 }
254
255 let item_clone = item.clone();
256 if let Ok(item_enum) = syn::parse::<syn::ItemEnum>(item_clone.clone()) {
257 return user::expand_caps_enum(args, item_enum);
258 }
259
260 let item_clone = item.clone();
261 if let Ok(item_impl) = syn::parse::<syn::ItemImpl>(item_clone) {
262 return user::expand_caps_impl(args, item_impl);
263 }
264
265 syn::Error::new(
266 proc_macro2::Span::call_site(),
267 "caps_bound supports fn, struct, enum, or impl",
268 )
269 .to_compile_error()
270 .into()
271}
272
273/// Create a capability set type from a list of capabilities.
274///
275/// # Usage
276/// ```ignore
277/// // Define capability set type
278/// type MyCaps = caps![CanRead, CanWrite];
279///
280/// // Empty set
281/// type NoCaps = caps![];
282///
283/// // Use in function signature
284/// fn process<C: Evaluate<CanRead, Out = Present>>() { }
285/// process::<caps![CanRead, CanWrite]>();
286/// ```
287#[proc_macro]
288pub fn caps(input: TokenStream) -> TokenStream {
289 let input = parse_macro_input!(input as user::CapsInput);
290 let types: Vec<_> = input.types.into_iter().collect();
291
292 if let Err(err) = user::check_duplicates(&types) {
293 return err.to_compile_error().into();
294 }
295
296 user::build_capset(&types).into()
297}
298
299/// Create a capability set type (alias for `caps!`).
300#[proc_macro]
301pub fn cap_set(input: TokenStream) -> TokenStream {
302 let input = parse_macro_input!(input as user::CapsInput);
303 let types: Vec<_> = input.types.into_iter().collect();
304
305 if let Err(err) = user::check_duplicates(&types) {
306 return err.to_compile_error().into();
307 }
308
309 user::build_capset(&types).into()
310}
311
312/// Batch define capabilities with auto-generated `Cap` suffix.
313///
314/// # Usage
315/// ```ignore
316/// define_capabilities! {
317/// LinksChecked => "Links have been checked",
318/// LinksResolved => "Links have been resolved",
319/// SvgOptimized => "SVG content has been optimized",
320/// }
321/// // Generates: LinksCheckedCap, LinksResolvedCap, SvgOptimizedCap
322/// // Plus HasXxxCap and NotHasXxxCap traits for each
323/// ```
324#[proc_macro]
325pub fn define_capabilities(input: TokenStream) -> TokenStream {
326 let input = parse_macro_input!(input as user::DefineCapabilitiesInput);
327 user::expand_define_capabilities(input).into()
328}
329
330/// Derive macro to automatically implement the `Capability` trait.
331///
332/// Computes a BLAKE3 hash of the struct name and generates a `HashStream` type.
333///
334/// # Usage
335/// ```ignore
336/// #[derive(Capability)]
337/// struct CanRead;
338///
339/// #[derive(Capability)]
340/// struct CanWrite;
341///
342/// // Now you can use:
343/// type MyCaps = caps![CanRead, CanWrite];
344/// ```
345#[proc_macro_derive(Capability)]
346pub fn derive_capability(input: TokenStream) -> TokenStream {
347 let input = parse_macro_input!(input as syn::DeriveInput);
348 user::expand_derive_capability(input).into()
349}
350
351/// Derive macro to auto-detect standard trait implementations.
352///
353/// This is the recommended way to enable `caps_check!` for user-defined types.
354///
355/// # Usage
356/// ```ignore
357/// #[derive(Clone, Debug, AutoCaps)]
358/// struct MyType { data: String }
359///
360/// // Now you can check traits:
361/// assert!(caps_check!(MyType: Clone));
362/// assert!(caps_check!(MyType: Debug));
363/// assert!(!caps_check!(MyType: Copy));
364/// ```
365#[proc_macro_derive(AutoCaps)]
366pub fn derive_autocaps(input: TokenStream) -> TokenStream {
367 let input = parse_macro_input!(input as syn::DeriveInput);
368 user::expand_derive_autocaps(input).into()
369}
370
371/// Attribute macro to enable a trait for the caps system.
372///
373/// Use this on trait definitions to allow `caps_check!(T: TraitName)`.
374///
375/// # Usage
376/// ```ignore
377/// #[trait_autocaps]
378/// trait Serializable {
379/// fn serialize(&self) -> Vec<u8>;
380/// }
381///
382/// // Now you can check:
383/// assert!(caps_check!(MySerializableType: Serializable));
384/// ```
385#[proc_macro_attribute]
386pub fn trait_autocaps(attr: TokenStream, item: TokenStream) -> TokenStream {
387 let _ = attr; // Unused for now
388 user::expand_trait_autocaps(item)
389}
390
391/// Derive macro to create capability-tracked structs with PhantomData.
392///
393/// Automatically adds a `_caps: PhantomData<C>` field and conversion methods.
394///
395/// # Usage
396/// ```ignore
397/// #[derive(CapHolder)]
398/// struct Doc {
399/// content: String,
400/// }
401///
402/// // Expands to:
403/// // struct Doc<C = Empty> {
404/// // content: String,
405/// // _caps: PhantomData<C>,
406/// // }
407///
408/// // Now use it with capabilities:
409/// let doc: Doc<caps![Parsed]> = doc.with_caps();
410/// ```
411#[proc_macro_derive(CapHolder)]
412pub fn derive_cap_holder(input: TokenStream) -> TokenStream {
413 let input = parse_macro_input!(input as syn::DeriveInput);
414 user::capability::expand_derive_cap_holder(input).into()
415}
416
417/// #[specialize] attribute macro for distributed specialization across files.
418///
419/// Mark individual items as default with `#[specialize(default)]`.
420/// Supports multi-generic constraints.
421///
422/// # Usage
423/// ```ignore
424/// trait MyTrait {
425/// type Output;
426/// fn describe(&self) -> Self::Output;
427/// }
428///
429/// // Most general (default) implementation
430/// #[specialize(default)]
431/// impl<T> MyTrait for T {
432/// type Output = ();
433/// fn describe(&self) -> Self::Output { () }
434/// }
435///
436/// // More specific - with constraint
437/// #[specialize(T: Clone)]
438/// impl<T> MyTrait for T {
439/// type Output = T;
440/// fn describe(&self) -> Self::Output { self.clone() }
441/// }
442///
443/// // Multiple generics
444/// #[specialize(T: Clone, U: Copy)]
445/// impl<T, U> Pair<T, U> for (T, U) { ... }
446///
447/// // Most specific - concrete type
448/// #[specialize]
449/// impl MyTrait for String {
450/// fn describe(&self) -> Self::Output { self.clone() }
451/// }
452/// ```
453#[proc_macro_attribute]
454pub fn specialize(attr: TokenStream, item: TokenStream) -> TokenStream {
455 user::specialize::expand_specialize_attr(attr, item)
456}
457
458/// Nightly-like specialization block syntax on Stable Rust.
459///
460/// # Features
461/// - `default fn` / `default type` - fine-grained control over what can be specialized
462/// - Associated type specialization
463/// - Multi-level specialization chains (A < B < C < ...)
464/// - Custom trait-to-capability mapping via `#[map(MyTrait => IsMyTrait)]`
465/// - Overlap detection with helpful error messages
466///
467/// # Usage
468/// ```ignore
469/// specialization! {
470/// trait MyTrait {
471/// type Output;
472/// fn method(&self) -> Self::Output;
473/// }
474///
475/// impl<T> MyTrait for T {
476/// default type Output = ();
477/// default fn method(&self) -> Self::Output { () }
478/// }
479///
480/// impl<T: Clone> MyTrait for T {
481/// type Output = T;
482/// fn method(&self) -> Self::Output { self.clone() }
483/// }
484///
485/// // Most specific
486/// impl MyTrait for String {
487/// fn method(&self) -> Self::Output { self.clone() }
488/// }
489/// }
490/// ```
491#[proc_macro]
492pub fn specialization(input: TokenStream) -> TokenStream {
493 user::specialize::expand_specialize_macro(input)
494}
495
496/// Nightly-like specialization for inherent impls.
497///
498/// # Usage
499/// ```ignore
500/// specialization_inherent! {
501/// impl<T> MyStruct<T> {
502/// default fn do_something(&self) { /* fallback */ }
503/// }
504///
505/// impl<T: Clone> MyStruct<T> {
506/// fn do_something(&self) { /* when T: Clone */ }
507/// }
508/// }
509/// ```
510#[proc_macro]
511pub fn specialization_inherent(input: TokenStream) -> TokenStream {
512 user::specialize::expand_specialize_inherent(input)
513}
514
515// Keep old names as aliases for backwards compatibility
516/// Alias for `specialization!` (backwards compatibility)
517#[proc_macro]
518pub fn specialize_block(input: TokenStream) -> TokenStream {
519 user::specialize::expand_specialize_macro(input)
520}
521
522/// Alias for `specialization_inherent!` (backwards compatibility)
523#[proc_macro]
524pub fn specialize_inherent(input: TokenStream) -> TokenStream {
525 user::specialize::expand_specialize_inherent(input)
526}
527
528/// Legacy alias - use `#[specialize]` instead
529#[proc_macro_attribute]
530pub fn specialization_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
531 user::specialize::expand_specialize_attr(attr, item)
532}
533
534/// Check if types satisfy trait constraints with boolean expression support.
535///
536/// Returns `true` or `false` at runtime based on compile-time trait detection.
537///
538/// # Syntax: `caps_check!(Type: Expr, ...)`
539///
540/// Supports multiple checks in one call. All checks must pass for result to be true.
541///
542/// ```ignore
543/// use std::fmt::Debug;
544/// use tola_caps::caps_check;
545///
546/// // Single check
547/// assert!(caps_check!(String: Clone));
548/// assert!(!caps_check!(String: Copy));
549///
550/// // Boolean expressions
551/// assert!(caps_check!(i32: Clone & Copy));
552/// assert!(caps_check!(String: Clone | Copy));
553/// assert!(caps_check!(String: Clone & !Copy));
554/// assert!(caps_check!(i32: (Clone | Copy) & Debug));
555///
556/// // Multiple checks (all must pass)
557/// assert!(caps_check!(String: Clone, i32: Copy));
558/// assert!(caps_check!(String: Clone & !Copy, i32: Clone & Copy));
559///
560/// // Mix concrete and generic types
561/// fn check<T: AutoCaps>() -> bool {
562/// caps_check!(T: Clone, String: Debug)
563/// }
564///
565/// // Custom traits work on concrete types
566/// trait MyTrait {}
567/// impl MyTrait for String {}
568/// assert!(caps_check!(String: MyTrait));
569/// ```
570#[proc_macro]
571pub fn caps_check(input: TokenStream) -> TokenStream {
572 let input = parse_macro_input!(input as CapsCheckInput);
573 expand_caps_check(input).into()
574}
575
576/// Define a type capability marker.
577///
578/// # Usage
579/// ```ignore
580/// define_type_cap!(String); // Generates TypeIsString marker struct
581/// define_type_cap!(Vec); // Generates TypeIsVec marker struct
582///
583/// // Use for type-based specialization
584/// impl<T: TypeIsString> MyTrait for T { ... }
585/// ```
586#[proc_macro]
587pub fn define_type_cap(input: TokenStream) -> TokenStream {
588 user::define_type_cap(input)
589}
590
591/// Generate capability marker and detection for a custom trait.
592///
593/// For `derive_trait_cap!(MySerializable)` generates:
594/// - `IsMySerializable` - capability marker
595/// - `MySerializableFallback` - fallback trait
596/// - Inherent const `IS_MY_SERIALIZABLE` for implementing types
597///
598/// # Example
599/// ```ignore
600/// trait MySerializable { fn serialize(&self) -> Vec<u8>; }
601/// derive_trait_cap!(MySerializable);
602///
603/// // Use in specialize! - auto-detected
604/// specialize! {
605/// impl<T: MySerializable> Format for T { /* ... */ }
606/// }
607/// ```
608#[proc_macro]
609pub fn derive_trait_cap(input: TokenStream) -> TokenStream {
610 user::derive_trait_cap(input)
611}
612
613/// Attribute macro to automatically implement AutoCaps and AutoCapSet for a type.
614///
615/// # Usage
616/// ```ignore
617/// #[auto_caps]
618/// struct MyType {
619/// data: String,
620/// }
621///
622/// // Now you can use caps_check! on MyType
623/// assert!(caps_check!(MyType, Clone));
624/// ```
625#[proc_macro_attribute]
626pub fn auto_caps(attr: TokenStream, item: TokenStream) -> TokenStream {
627 user::expand_auto_caps(attr, item)
628}
629
630/// Unified capability attribute macro.
631///
632/// # On Trait: Register trait for caps system
633/// ```ignore
634/// #[cap]
635/// trait Serializable {
636/// fn serialize(&self) -> Vec<u8>;
637/// }
638/// // Generates: IsSerializable marker, is_serializable::<T>() function
639/// // Now usable in specialize! without #[map]
640/// ```
641///
642/// # On Struct/Enum: Auto-detect standard traits
643/// ```ignore
644/// #[cap]
645/// struct MyType { data: String }
646/// // Enables trait detection via caps system
647/// ```
648///
649/// **DEPRECATED**: Use `#[derive(AutoCaps)]` for types and `#[trait_autocaps]` for traits.
650#[deprecated(note = "Use `#[derive(AutoCaps)]` for types and `#[trait_autocaps]` for traits instead")]
651#[proc_macro_attribute]
652pub fn cap(attr: TokenStream, item: TokenStream) -> TokenStream {
653 user::expand_cap_attr(attr, item)
654}
655
656// =============================================================================
657// caps_check! Implementation (Unified)
658// =============================================================================
659
660/// Single type check: `Type: Expr`
661struct TypeCheck {
662 ty: syn::Type,
663 expr: common::BoolExpr,
664}
665
666impl syn::parse::Parse for TypeCheck {
667 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
668 let ty: syn::Type = input.parse()?;
669 input.parse::<syn::Token![:]>()?;
670 let expr: common::BoolExpr = input.parse()?;
671 Ok(TypeCheck { ty, expr })
672 }
673}
674
675/// Input for caps_check! macro: one or more type checks
676struct CapsCheckInput {
677 checks: Vec<TypeCheck>,
678}
679
680impl syn::parse::Parse for CapsCheckInput {
681 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
682 let mut checks = Vec::new();
683
684 // Parse first check (required)
685 checks.push(input.parse()?);
686
687 // Parse additional checks separated by commas
688 while input.peek(syn::Token![,]) {
689 input.parse::<syn::Token![,]>()?;
690 if input.is_empty() {
691 break;
692 }
693 checks.push(input.parse()?);
694 }
695
696 Ok(CapsCheckInput { checks })
697 }
698}
699
700fn expand_caps_check(input: CapsCheckInput) -> proc_macro2::TokenStream {
701 if input.checks.len() == 1 {
702 let check = &input.checks[0];
703 let ty = &check.ty;
704 let inner = common::generate_unified_check(&check.expr, ty);
705
706 // Reference user's type before internal imports to avoid unused import warnings
707 quote::quote! {
708 {
709 fn __use_type<__T>(_: ::core::marker::PhantomData<__T>) {}
710 __use_type::<#ty>(::core::marker::PhantomData);
711 #inner
712 }
713 }
714 } else {
715 // Multiple checks - AND them together
716 let type_refs: Vec<_> = input.checks.iter()
717 .map(|c| {
718 let ty = &c.ty;
719 quote::quote! { __use_type::<#ty>(::core::marker::PhantomData); }
720 })
721 .collect();
722 let check_exprs: Vec<_> = input.checks.iter()
723 .map(|c| common::generate_unified_check(&c.expr, &c.ty))
724 .collect();
725
726 quote::quote! {
727 {
728 fn __use_type<__T>(_: ::core::marker::PhantomData<__T>) {}
729 #(#type_refs)*
730 (#(#check_exprs)&&*)
731 }
732 }
733 }
734}