//! # irys — Compile-Time Trait Reflection for Rust
//!
//! **If it can be expressed as a trait bound, you can reflect over it.**
//!
//! Automatically discover which traits a type implements at compile time,
//! without per-type annotation.
//!
//! ```rust
//! use irys::*;
//! use std::fmt;
//!
//! // 1. Define a capability (marker struct + what trait object it maps to)
//! struct DisplayCap;
//! impl Capability for DisplayCap {
//!     type Handle = dyn fmt::Display;
//! }
//!
//! // 2. Register it (one-time, blanket — covers ALL types that implement Display)
//! register_capability! {
//!     slot: 0,
//!     cap: DisplayCap,
//!     trait_bound: fmt::Display,
//! }
//!
//! // 3. Reflect any value — capabilities are detected automatically
//! let envelope = reflect!("hello world");
//! assert!(envelope.has::<DisplayCap>());
//!
//! let display = envelope.get::<DisplayCap>().unwrap();
//! assert_eq!(format!("{}", display), "hello world");
//! ```
//!
//! ## Why irys?
//!
//! Every existing reflection system in Rust requires **per-type registration**:
//!
//! | System | Registration cost | Trait discovery? |
//! |--------|-------------------|-----------------|
//! | **irys** | **1 per trait** (blanket covers all types) | Yes, automatic |
//! | `bevy_reflect` | 1 per type + 1 per type×trait | Partial (explicit `#[reflect(Trait)]`) |
//! | `typetag` | 1 per type×trait | No (serde only) |
//! | `inventory`/`linkme` | 1 per type | No |
//! | `std::any::Any` | None | No (downcast only) |
//!
//! With irys, you register a capability **once** and it automatically applies to every type
//! that satisfies the trait bound — past, present, and future. No derives, no proc macros,
//! no per-type boilerplate.
//!
//! ## Core Concepts
//!
//! ### Capabilities
//!
//! A **capability** is a marker struct that maps to a trait object type. It answers the
//! question "can this value do X?":
//!
//! ```rust
//! # use irys::*;
//! # mod erased_serde { pub trait Serialize {} }
//! struct SerializeCap;
//! impl Capability for SerializeCap {
//!     type Handle = dyn erased_serde::Serialize;
//! }
//! ```
//!
//! ### Registries
//!
//! A **registry** is a namespace for capabilities. It isolates your capability slots from
//! other libraries so they can't collide:
//!
//! ```rust
//! # use irys::*;
//! # use std::fmt;
//! struct MyRegistry;
//!
//! # struct DebugCap;
//! # impl Capability for DebugCap { type Handle = dyn fmt::Debug; }
//! register_capability! {
//!     registry: MyRegistry,
//!     slot: 0,  // slot 0 in YOUR registry — no conflict with anyone else's slot 0
//!     cap: DebugCap,
//!     trait_bound: fmt::Debug,
//! }
//! ```
//!
//! When no registry is specified, [`DefaultRegistry`] is used.
//!
//! ### Slots
//!
//! Each capability occupies a **slot** (a number) within a registry. The slot determines
//! which compile-time probe fires during reflection. Two capabilities at the same slot
//! in the same registry will produce a compile error — this is intentional collision
//! detection.
//!
//! You only probe the slots you use. 5 capabilities? Probe 5 slots. This means compile
//! time scales with what YOU care about, not what exists in the ecosystem.
//!
//! ### Envelopes — The Ownership Model
//!
//! irys follows the same ownership model as `Vec<T>` / `&[T]` / `&mut [T]`:
//!
//! | Type | Created by | Access |
//! |------|-----------|--------|
//! | [`Envelope`] | [`reflect!`] | Full ownership: get, get_mut, into_data |
//! | [`EnvelopeRef`] | [`reflect_ref!`] or [`Envelope::as_ref`] | Shared: get, data |
//! | [`EnvelopeMut`] | [`reflect_mut!`] or [`Envelope::as_mut`] | Mutable: get, get_mut, data_mut |
//!
//! ```rust
//! # use irys::*;
//! # use std::fmt;
//! # struct DisplayCap;
//! # impl Capability for DisplayCap { type Handle = dyn fmt::Display; }
//! # register_capability! { slot: 0, cap: DisplayCap, trait_bound: fmt::Display }
//! // Owned — consumes the value
//! let envelope = reflect!(42i32);
//!
//! // Shared borrow — value remains available
//! let value = 42i32;
//! let envelope_ref = reflect_ref!(&value);
//! assert_eq!(value, 42); // still usable
//!
//! // Mutable borrow — can mutate through capabilities
//! # trait Resettable { fn reset(&mut self); }
//! # struct ResettableCap;
//! # impl Capability for ResettableCap { type Handle = dyn Resettable; }
//! # register_capability! { slot: 1, cap: ResettableCap, trait_bound: Resettable }
//! # struct Counter { count: u32 }
//! # impl Resettable for Counter { fn reset(&mut self) { self.count = 0; } }
//! let mut counter = Counter { count: 99 };
//! {
//!     let mut env = reflect_mut!(&mut counter);
//!     env.get_mut::<ResettableCap>().unwrap().reset();
//! }
//! assert_eq!(counter.count, 0); // mutated in place
//! ```
//!
//! Conversions work like you'd expect:
//! - `envelope.as_ref()` → `EnvelopeRef` (borrows the envelope's map, zero-cost)
//! - `envelope.as_mut()` → `EnvelopeMut` (borrows the envelope's map, zero-cost)
//! - `envelope_mut.as_ref()` → `EnvelopeRef` (downgrade to shared)
//!
//! ## Registries & Slot Ranges
//!
//! By default, `reflect!` probes the [`DefaultRegistry`] for 256 slots. You can customize
//! which registries and how many slots to probe:
//!
//! ```rust
//! # use irys::*;
//! # struct CoreRegistry;
//! # struct ObsRegistry;
//! # let value = 42i32;
//! let envelope = reflect!(value, [
//!     { registry: CoreRegistry, slots: 0..5 },
//!     { registry: ObsRegistry, slots: 0..3 },
//! ]);
//! ```
//!
//! This gives you precise control over compile-time cost: only probe the slots you actually
//! use. If you have 5 capabilities, probe 5 slots — not 256.
//!
//! Registries probed later **override** earlier ones for the same capability (last-write-wins).
//! This gives you natural override/specialization semantics without language-level specialization.
//!
//! ## The `Reflectable` Trait
//!
//! For generic code that needs to work with reflected values, implement [`Reflectable`].
//! The [`impl_reflectable!`] macro does this in one line:
//!
//! ```rust
//! # use irys::*;
//! # struct MyRegistry;
//! struct MyEvent { data: String }
//!
//! impl_reflectable!(MyEvent, { registries: [{ registry: MyRegistry, slots: 0..10 }] });
//!
//! // Generic code can accept anything Reflectable (with any config)
//! fn publish<C>(event: impl Reflectable<C>) {
//!     let envelope = event.reflect();
//!     // route based on capabilities...
//! }
//!
//! // Also works with borrowed access
//! fn inspect<C>(event: &impl Reflectable<C>) {
//!     let envelope_ref = event.reflect_ref();
//!     // read-only capability access...
//! }
//! ```
//!
//! ### Orphan Rule Dodge
//!
//! The `C` type parameter on `Reflectable<C>` lets downstream crates implement reflection
//! for upstream types without violating Rust's orphan rule:
//!
//! ```rust
//! # use irys::*;
//! // Upstream crate defines this type — you can't modify it
//! struct ThirdPartyEvent { id: u64 }
//!
//! // Your crate defines a config marker (local type = orphan rule satisfied)
//! struct MyConfig;
//!
//! // Now legal! MyConfig is local, so you can impl Reflectable<MyConfig> for anything
//! impl_reflectable!(ThirdPartyEvent, { config: MyConfig });
//!
//! // Library functions generic over C accept any config
//! fn process<C>(event: impl Reflectable<C>) {
//!     let envelope = event.reflect();
//! }
//! ```
//!
//! This is analogous to how `bevy_reflect` uses `#[derive(Reflect)]` — but here it's
//! a one-line macro invocation with no proc macros.
//!
//! ## Generic Capabilities
//!
//! The real power of irys: register a capability with a generic type parameter, and the
//! compiler resolves it for every concrete instantiation:
//!
//! ```rust
//! # use irys::*;
//! # use std::marker::PhantomData;
//! # mod futures_stream { pub trait Stream { type Item; } }
//! # use futures_stream::Stream;
//! struct StreamCap<I>(PhantomData<I>);
//! impl<I: 'static> Capability for StreamCap<I> {
//!     type Handle = dyn Stream<Item = I>;
//! }
//!
//! // Register ONCE — works for ALL item types
//! register_capability! {
//!     slot: 0,
//!     cap: StreamCap<I>,
//!     trait_bound: Stream<Item = I>,
//!     generics: [I: 'static],
//! }
//!
//! # struct Event;
//! # let envelope = reflect!(0u8);
//! // Query with specific types
//! envelope.has::<StreamCap<String>>();    // does it stream strings?
//! envelope.has::<StreamCap<Event>>();     // does it stream events?
//! ```
//!
//! This works with any trait that has associated types: `Iterator<Item=T>`,
//! `Future<Output=T>`, `Stream<Item=T>`, `AsRef<T>`, etc.
//!
//! **No other Rust reflection library can do this.** The Rust compiler does the heavy
//! lifting: it infers type parameters, catches ambiguities at compile time, and eliminates
//! unmatched probes entirely.
//!
//! ### The `register_capability!` Macro
//!
//! Fields can be provided in **any order**:
//!
//! | Field | Required | Description |
//! |-------|----------|-------------|
//! | `slot` | Yes | Slot number within the registry |
//! | `cap` | Yes | The capability marker type |
//! | `trait_bound` | Yes | Trait bound(s) that types must satisfy |
//! | `registry` | No | Registry (defaults to [`DefaultRegistry`]) |
//! | `generics` | No | Extra generic params: `[I: 'static, U: Clone]` |
//! | `where` | No | Additional where clause bounds |
//!
//! ## Common Patterns
//!
//! ### Adapter Traits — Compositional Capabilities
//!
//! The most powerful pattern in irys: define an adapter trait with a blanket impl that
//! composes multiple constraints, register it once, and it's automatically detected on
//! any type satisfying the combination.
//!
//! Example: "I don't care WHAT this iterates — just that each item is serializable":
//!
//! ```rust
//! # use irys::*;
//! # mod erased_serde { pub trait Serialize: 'static {} impl<T: 'static> Serialize for T {} }
//! // The adapter trait — erases the item type
//! trait SerializableIter {
//!     fn next_ser(&mut self) -> Option<Box<dyn erased_serde::Serialize>>;
//! }
//!
//! // Blanket impl — any Iterator with Serialize items qualifies
//! impl<T: Iterator> SerializableIter for T
//! where T::Item: erased_serde::Serialize + 'static {
//!     fn next_ser(&mut self) -> Option<Box<dyn erased_serde::Serialize>> {
//!         self.next().map(|item| Box::new(item) as _)
//!     }
//! }
//!
//! struct SerializableIterCap;
//! impl Capability for SerializableIterCap {
//!     type Handle = dyn SerializableIter;
//! }
//!
//! register_capability! { slot: 0, cap: SerializableIterCap, trait_bound: SerializableIter }
//!
//! // Now ANY iterator with serializable items is detected automatically:
//! # #[derive(Clone)] struct LogEntry;
//! # #[derive(Clone)] struct Metric;
//! let logs = vec![LogEntry, LogEntry].into_iter();
//! let metrics = vec![Metric, Metric].into_iter();
//!
//! assert!(reflect!(logs).has::<SerializableIterCap>());
//! assert!(reflect!(metrics).has::<SerializableIterCap>());
//! ```
//!
//! This pattern completely skips the need to probe for every concrete item type.
//! No other Rust reflection library supports this — it requires blanket detection
//! combined with the compiler's full trait resolution, which only irys provides.
//!
//! ### Cloning an Envelope
//!
//! `Envelope` can't implement `Clone` directly (the inner value is type-erased). Instead,
//! register `Clone` as a capability, then use [`caps()`](Envelope::caps) +
//! [`from_raw()`](Envelope::from_raw) to reconstruct:
//!
//! ```rust
//! # use irys::*;
//! use std::any::Any;
//!
//! trait DynClone: Send + Sync {
//!     fn clone_boxed(&self) -> Box<dyn Any + Send + Sync>;
//! }
//!
//! impl<T: Clone + Send + Sync + 'static> DynClone for T {
//!     fn clone_boxed(&self) -> Box<dyn Any + Send + Sync> {
//!         Box::new(self.clone())
//!     }
//! }
//!
//! struct CloneCap;
//! impl Capability for CloneCap {
//!     type Handle = dyn DynClone;
//! }
//!
//! register_capability! {
//!     slot: 0,
//!     cap: CloneCap,
//!     trait_bound: DynClone,
//! }
//!
//! // Clone an envelope:
//! # #[derive(Clone)] struct MyData(i32);
//! let envelope = reflect!(MyData(42));
//! let cloned_data = envelope.get::<CloneCap>().unwrap().clone_boxed();
//! let cloned_envelope = Envelope::from_raw(cloned_data, envelope.caps().clone());
//! ```
//!
//! The capability map clone is cheap (just `Arc` refcount bumps internally). If the map
//! doesn't match the data type (e.g., after calling `from_raw` with wrong data),
//! `get()` safely returns `None` — no panics.
//!
//! ### Event Bus Routing
//!
//! Route heterogeneous events based on discovered capabilities:
//!
//! ```rust
//! # use irys::*;
//! # use std::sync::{mpsc, Arc};
//! # struct PriorityCap;
//! # impl Capability for PriorityCap { type Handle = dyn Priority; }
//! # trait Priority { fn is_critical(&self) -> bool; }
//! # struct SerializeCap;
//! # impl Capability for SerializeCap { type Handle = dyn std::fmt::Debug; }
//! # fn escalate(_: &Arc<Envelope>) {}
//! # fn persist(_: &Arc<Envelope>) {}
//! fn router(rx: mpsc::Receiver<Arc<Envelope>>) {
//!     while let Ok(envelope) = rx.recv() {
//!         if let Some(prio) = envelope.get::<PriorityCap>() {
//!             if prio.is_critical() {
//!                 escalate(&envelope);
//!             }
//!         }
//!         if envelope.has::<SerializeCap>() {
//!             persist(&envelope);
//!         }
//!     }
//! }
//! ```
//!
//! ### Composing with Other Reflection Libraries
//!
//! irys can wrap other reflection systems as capabilities:
//!
//! ```rust
//! # use irys::*;
//! # mod bevy_reflect { pub trait Reflect: 'static {} }
//! struct ReflectCap;
//! impl Capability for ReflectCap {
//!     type Handle = dyn bevy_reflect::Reflect;
//! }
//!
//! register_capability! {
//!     slot: 0,
//!     cap: ReflectCap,
//!     trait_bound: bevy_reflect::Reflect,
//! }
//!
//! // Now any type implementing Reflect is automatically detected
//! // irys handles discovery, bevy_reflect handles structural introspection
//! ```
//!
//! ## How It Works
//!
//! irys uses a technique called **autoref specialization** combined with **const generics**
//! to achieve compile-time trait detection on stable Rust. Here's the mechanism:
//!
//! 1. **`register_capability!`** generates two impls for each capability:
//!    - An inherent-like impl on `Probe<T, Registry, N>` with a trait bound (`T: MyTrait`)
//!    - A blanket trait impl on `&Probe<T, Registry, N>` with no bound (the fallback)
//!
//! 2. **`reflect!`** expands (via `seq!`) into a loop calling `.probe()` for each slot.
//!    Rust's method resolution prefers the inherent impl when the bound is satisfied,
//!    falling back to the trait impl (which is a no-op) when it's not.
//!
//! 3. **The compiler resolves this statically** — there's no runtime branching. For
//!    capabilities a type doesn't have, the optimizer eliminates the no-op entirely.
//!
//! 4. **Registries** are just type parameters on `Probe`, giving each namespace its own
//!    set of inherent impls that can't collide with other registries.
//!
//! The result: zero runtime cost for undetected capabilities, and the entire detection
//! happens at compile time.
//!
//! ## Limitations
//!
//! - **Concrete types only at the `reflect!()` call site**: The autoref trick requires the
//!   compiler to see the concrete type. In generic functions where `T` is abstract, use the
//!   [`Reflectable`] trait pattern (implement `Reflectable` on concrete types, then bound
//!   generic code with `T: Reflectable`). This is the same constraint every Rust reflection
//!   library has — bevy_reflect requires `#[derive(Reflect)]` on concrete types too.
//!
//! - **Capabilities only propagate downward**: A `reflect!()` call can only detect
//!   capabilities whose `register_capability!` was visible at compile time — i.e., defined
//!   in the same crate or in a dependency. If crate A calls `reflect!()` and crate B
//!   (which depends on A) registers a new capability, crate A will NOT see it. This is a
//!   fundamental consequence of Rust's compilation model: upstream crates are compiled
//!   before downstream crates exist.
//!
//!   **Workarounds**: Have the upstream crate accept a pre-constructed [`Envelope`], a
//!   `fn() -> Envelope`, or a type implementing [`Reflectable`]. This pushes the `reflect!()`
//!   call to the downstream crate where all capabilities are visible.
//!
//! - **Slot management is manual**: You pick slot numbers. The compiler catches collisions
//!   (same registry + same slot = compile error), but you manage the allocation. Use
//!   registries to isolate your slots from other libraries.
//!
//! - **Ambiguous generic registrations**: If a type implements `Trait<A>` AND `Trait<B>`,
//!   a generic registration for `Trait<T>` will fail with a compile error — the compiler
//!   can't infer which `T` to use. Register concrete instances instead (`Cap<A>` at slot 0,
//!   `Cap<B>` at slot 1). This is the compiler protecting you from ambiguity.
//!
//! - **`unsafe` internally**: Fat pointer transport between type-erased closures requires
//!   `transmute_copy`. This is sound (trait object fat pointer layout is guaranteed) but
//!   the code does contain `unsafe` blocks internally. The public API is fully safe.

use std::any::{Any, TypeId};
use std::borrow::Cow;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc;

pub use seq_macro::seq;

/// The default registry used when no registry is specified in [`register_capability!`] or [`reflect!`].
///
/// All capabilities registered without an explicit `registry: ...` go into this registry.
/// The default `reflect!(value)` call probes this registry for slots 0..256.
pub struct DefaultRegistry;

/// The default config used when no config is specified in [`impl_reflectable!`].
///
/// This is a marker type that parameterizes [`Reflectable`]. Downstream crates can define
/// their own config types and implement `Reflectable<MyConfig>` for types they control,
/// effectively dodging orphan rule restrictions — since the config type is local to their crate.
pub struct DefaultConfig;

/// A capability defines what trait object a type can be cast to.
///
/// Implement this on a marker struct to define a new capability:
///
/// ```rust
/// # use irys::Capability;
/// # mod erased_serde { pub trait Serialize: 'static {} }
/// struct SerializeCap;
/// impl Capability for SerializeCap {
///     type Handle = dyn erased_serde::Serialize;
/// }
/// ```
///
/// The `Handle` type is the trait object you'll get back from [`Envelope::get`].
pub trait Capability: 'static {
    /// The trait object type this capability provides access to.
    type Handle: ?Sized + 'static;
}

#[derive(Clone)]
struct CastFn {
    cast_ref: Arc<dyn Fn(&dyn Any) -> Option<[usize; 2]> + Send + Sync>,
    cast_mut: Arc<dyn Fn(&mut dyn Any) -> Option<[usize; 2]> + Send + Sync>,
}

/// Storage for detected capabilities and their type-erased cast functions.
///
/// You typically don't interact with this directly — it's created internally by [`reflect!`]
/// and stored inside [`Envelope`].
#[derive(Clone)]
pub struct CapabilityMap {
    entries: HashMap<TypeId, CastFn>,
}

impl CapabilityMap {
    pub fn new() -> Self {
        Self {
            entries: HashMap::new(),
        }
    }

    pub fn insert_cast<C: Capability>(
        &mut self,
        cast_ref: impl Fn(&dyn Any) -> Option<&C::Handle> + Send + Sync + 'static,
        cast_mut: impl Fn(&mut dyn Any) -> Option<&mut C::Handle> + Send + Sync + 'static,
    ) {
        self.entries.insert(
            TypeId::of::<C>(),
            CastFn {
                cast_ref: Arc::new(move |any| {
                    let handle: &C::Handle = cast_ref(any)?;
                    Some(unsafe { std::mem::transmute_copy::<&C::Handle, [usize; 2]>(&handle) })
                }),
                cast_mut: Arc::new(move |any| {
                    let handle: &mut C::Handle = cast_mut(any)?;
                    Some(unsafe { std::mem::transmute_copy::<&mut C::Handle, [usize; 2]>(&handle) })
                }),
            },
        );
    }

    pub fn has<C: Capability>(&self) -> bool {
        self.entries.contains_key(&TypeId::of::<C>())
    }

    pub fn len(&self) -> usize {
        self.entries.len()
    }

    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    fn get_ref<C: Capability>(&self, data: &dyn Any) -> Option<[usize; 2]> {
        let cast_fn = self.entries.get(&TypeId::of::<C>())?;
        (cast_fn.cast_ref)(data)
    }

    fn get_mut<C: Capability>(&self, data: &mut dyn Any) -> Option<[usize; 2]> {
        let cast_fn = self.entries.get(&TypeId::of::<C>())?;
        (cast_fn.cast_mut)(data)
    }
}

/// A reflected value with its discovered capabilities (owned).
///
/// Created by [`reflect!`], an `Envelope` wraps the original value and provides
/// capability-based access to trait objects. This is the owned variant — analogous to
/// `Vec<T>`. For borrowed access, see [`EnvelopeRef`] and [`EnvelopeMut`].
///
/// # Conversions
///
/// Like `Vec<T>` → `&[T]` / `&mut [T]`:
/// - [`Envelope::as_ref`] → [`EnvelopeRef`]
/// - [`Envelope::as_mut`] → [`EnvelopeMut`]
///
/// # Thread Safety
///
/// `Envelope` is `Send + Sync` (the inner value is `Box<dyn Any + Send + Sync>`).
/// For shared access across threads, wrap in `Arc<Envelope>`.
pub struct Envelope {
    data: Box<dyn Any + Send + Sync>,
    caps: CapabilityMap,
}

impl Envelope {
    pub fn from_parts(data: impl Any + Send + Sync, caps: CapabilityMap) -> Self {
        Self {
            data: Box::new(data),
            caps,
        }
    }

    /// Construct an envelope from a pre-boxed value and a capability map.
    ///
    /// This is useful for reconstructing an envelope after cloning the inner value
    /// via a `DynClone` capability. If the capability map doesn't match the boxed type,
    /// `get()` will safely return `None` rather than panicking.
    pub fn from_raw(data: Box<dyn Any + Send + Sync>, caps: CapabilityMap) -> Self {
        Self { data, caps }
    }

    /// Get a shared reference to the capability map.
    pub fn caps(&self) -> &CapabilityMap {
        &self.caps
    }

    /// Borrow this envelope as an [`EnvelopeRef`] (read-only access).
    pub fn as_ref(&self) -> EnvelopeRef<'_> {
        EnvelopeRef {
            data: &*self.data,
            caps: Cow::Borrowed(&self.caps),
        }
    }

    /// Borrow this envelope as an [`EnvelopeMut`] (read + mutable trait access).
    pub fn as_mut(&mut self) -> EnvelopeMut<'_> {
        EnvelopeMut {
            data: &mut *self.data,
            caps: Cow::Borrowed(&self.caps),
        }
    }

    /// Get a shared reference to the capability's trait object.
    ///
    /// Returns `None` if the wrapped type doesn't implement the capability's trait bound.
    pub fn get<C: Capability>(&self) -> Option<&C::Handle> {
        let fat = self.caps.get_ref::<C>(&*self.data)?;
        unsafe {
            Some(&*std::mem::transmute_copy::<[usize; 2], *const C::Handle>(
                &fat,
            ))
        }
    }

    /// Get a mutable reference to the capability's trait object.
    ///
    /// Returns `None` if the wrapped type doesn't implement the capability's trait bound.
    pub fn get_mut<C: Capability>(&mut self) -> Option<&mut C::Handle> {
        let fat = self.caps.get_mut::<C>(&mut *self.data)?;
        unsafe { Some(&mut *std::mem::transmute_copy::<[usize; 2], *mut C::Handle>(&fat)) }
    }

    /// Check whether this envelope's value has a given capability.
    pub fn has<C: Capability>(&self) -> bool {
        self.caps.has::<C>()
    }

    /// Get a shared reference to the underlying concrete type.
    ///
    /// Returns `None` if `T` doesn't match the actual stored type.
    pub fn data<T: 'static>(&self) -> Option<&T> {
        self.data.downcast_ref()
    }

    /// Get a mutable reference to the underlying concrete type.
    ///
    /// Returns `None` if `T` doesn't match the actual stored type.
    pub fn data_mut<T: 'static>(&mut self) -> Option<&mut T> {
        self.data.downcast_mut()
    }

    /// Consume the envelope and recover the original value.
    ///
    /// Returns `None` if `T` doesn't match the actual stored type.
    pub fn into_data<T: 'static>(self) -> Option<T> {
        self.data.downcast().ok().map(|b| *b)
    }

    /// The number of capabilities detected on this value.
    pub fn capability_count(&self) -> usize {
        self.caps.len()
    }
}

/// A borrowed reflected value with read-only capability access.
///
/// Created by [`reflect_ref!`] or [`Envelope::as_ref`]. Analogous to `&[T]`.
/// Provides shared access to capabilities without consuming the original value.
///
/// # Example
///
/// ```rust
/// # use irys::*;
/// # use std::fmt;
/// # struct DisplayCap;
/// # impl Capability for DisplayCap { type Handle = dyn fmt::Display; }
/// # register_capability! { slot: 0, cap: DisplayCap, trait_bound: fmt::Display }
/// let value = 42i32;
/// let envelope_ref = reflect_ref!(&value);
/// assert!(envelope_ref.has::<DisplayCap>());
/// // value is still available here
/// assert_eq!(value, 42);
/// ```
pub struct EnvelopeRef<'a> {
    data: &'a dyn Any,
    caps: Cow<'a, CapabilityMap>,
}

impl<'a> EnvelopeRef<'a> {
    pub fn from_parts(data: &'a dyn Any, caps: CapabilityMap) -> Self {
        Self {
            data,
            caps: Cow::Owned(caps),
        }
    }

    /// Get a shared reference to the capability map.
    pub fn caps(&self) -> &CapabilityMap {
        &self.caps
    }

    /// Get a shared reference to the capability's trait object.
    ///
    /// Returns `None` if the wrapped type doesn't implement the capability's trait bound.
    pub fn get<C: Capability>(&self) -> Option<&C::Handle> {
        let fat = self.caps.get_ref::<C>(self.data)?;
        unsafe {
            Some(&*std::mem::transmute_copy::<[usize; 2], *const C::Handle>(
                &fat,
            ))
        }
    }

    /// Check whether this envelope's value has a given capability.
    pub fn has<C: Capability>(&self) -> bool {
        self.caps.has::<C>()
    }

    /// Get a shared reference to the underlying concrete type.
    ///
    /// Returns `None` if `T` doesn't match the actual stored type.
    pub fn data<T: 'static>(&self) -> Option<&T> {
        self.data.downcast_ref()
    }

    /// The number of capabilities detected on this value.
    pub fn capability_count(&self) -> usize {
        self.caps.len()
    }
}

/// A mutably borrowed reflected value with read + write capability access.
///
/// Created by [`reflect_mut!`] or [`Envelope::as_mut`]. Analogous to `&mut [T]`.
/// Provides mutable access to capabilities without consuming the original value.
///
/// # Example
///
/// ```rust
/// # use irys::*;
/// # use std::fmt;
/// # trait Resettable { fn reset(&mut self); fn value(&self) -> String; }
/// # struct ResettableCap;
/// # impl Capability for ResettableCap { type Handle = dyn Resettable; }
/// # register_capability! { slot: 0, cap: ResettableCap, trait_bound: Resettable }
/// # struct Counter { count: u32 }
/// # impl Resettable for Counter { fn reset(&mut self) { self.count = 0; } fn value(&self) -> String { format!("{}", self.count) } }
/// let mut value = Counter { count: 42 };
/// let mut envelope_mut = reflect_mut!(&mut value);
/// envelope_mut.get_mut::<ResettableCap>().unwrap().reset();
/// assert_eq!(value.count, 0);
/// ```
pub struct EnvelopeMut<'a> {
    data: &'a mut dyn Any,
    caps: Cow<'a, CapabilityMap>,
}

impl<'a> EnvelopeMut<'a> {
    pub fn from_parts(data: &'a mut dyn Any, caps: CapabilityMap) -> Self {
        Self {
            data,
            caps: Cow::Owned(caps),
        }
    }

    /// Get a shared reference to the capability map.
    pub fn caps(&self) -> &CapabilityMap {
        &self.caps
    }

    /// Downgrade to a read-only [`EnvelopeRef`].
    pub fn as_ref(&self) -> EnvelopeRef<'_> {
        EnvelopeRef {
            data: self.data,
            caps: Cow::Borrowed(&self.caps),
        }
    }

    /// Get a shared reference to the capability's trait object.
    ///
    /// Returns `None` if the wrapped type doesn't implement the capability's trait bound.
    pub fn get<C: Capability>(&self) -> Option<&C::Handle> {
        let fat = self.caps.get_ref::<C>(self.data)?;
        unsafe {
            Some(&*std::mem::transmute_copy::<[usize; 2], *const C::Handle>(
                &fat,
            ))
        }
    }

    /// Get a mutable reference to the capability's trait object.
    ///
    /// Returns `None` if the wrapped type doesn't implement the capability's trait bound.
    pub fn get_mut<C: Capability>(&mut self) -> Option<&mut C::Handle> {
        let fat = self.caps.get_mut::<C>(self.data)?;
        unsafe { Some(&mut *std::mem::transmute_copy::<[usize; 2], *mut C::Handle>(&fat)) }
    }

    /// Check whether this envelope's value has a given capability.
    pub fn has<C: Capability>(&self) -> bool {
        self.caps.has::<C>()
    }

    /// Get a shared reference to the underlying concrete type.
    ///
    /// Returns `None` if `T` doesn't match the actual stored type.
    pub fn data<T: 'static>(&self) -> Option<&T> {
        self.data.downcast_ref()
    }

    /// Get a mutable reference to the underlying concrete type.
    ///
    /// Returns `None` if `T` doesn't match the actual stored type.
    pub fn data_mut<T: 'static>(&mut self) -> Option<&mut T> {
        self.data.downcast_mut()
    }

    /// The number of capabilities detected on this value.
    pub fn capability_count(&self) -> usize {
        self.caps.len()
    }
}

/// Trait for types that know how to reflect themselves.
///
/// Provides owned, shared, and mutable reflection — analogous to how
/// `Any` provides `downcast`, `downcast_ref`, and `downcast_mut`.
///
/// The generic parameter `C` is a **config marker** — it allows multiple implementations
/// of `Reflectable` for the same type with different probing configurations. More importantly,
/// it lets downstream crates dodge the orphan rule: define your own config type (which is local
/// to your crate), then implement `Reflectable<MyConfig>` for any type — even types from
/// upstream crates.
///
/// # Manual Implementation
///
/// ```rust
/// # use irys::*;
/// struct MyEvent { data: String }
///
/// impl Reflectable for MyEvent {
///     fn reflect(self) -> Envelope { reflect!(self) }
///     fn reflect_ref(&self) -> EnvelopeRef<'_> { reflect_ref!(&*self) }
///     fn reflect_mut(&mut self) -> EnvelopeMut<'_> { reflect_mut!(&mut *self) }
/// }
/// ```
///
/// # Using the Helper Macro
///
/// ```rust
/// # use irys::*;
/// struct MyEvent { data: String }
///
/// impl_reflectable!(MyEvent);
///
/// // With custom registries:
/// # struct MyRegistry;
/// struct OtherEvent;
/// impl_reflectable!(OtherEvent, { registries: [{ registry: MyRegistry, slots: 0..5 }] });
/// ```
///
/// # Orphan Rule Dodge
///
/// ```rust
/// # use irys::*;
/// // Upstream crate defines a type:
/// struct UpstreamEvent { data: String }
///
/// // Your crate defines a config marker:
/// struct MyConfig;
///
/// // Now you can impl Reflectable<MyConfig> for UpstreamEvent — no orphan violation!
/// impl_reflectable!(UpstreamEvent, { config: MyConfig });
///
/// // A library function generic over config:
/// fn process<C>(event: impl Reflectable<C>) {
///     let envelope = event.reflect();
///     // ...
/// }
/// ```
pub trait Reflectable<C = DefaultConfig>: Send + Sync + 'static {
    fn reflect(self) -> Envelope;
    fn reflect_ref(&self) -> EnvelopeRef<'_>;
    fn reflect_mut(&mut self) -> EnvelopeMut<'_>;
}

/// Implement [`Reflectable`] for a type with minimal boilerplate.
///
/// # Basic Usage (DefaultConfig, DefaultRegistry, 256 slots)
///
/// ```rust
/// # use irys::*;
/// struct MyEvent { data: String }
/// impl_reflectable!(MyEvent);
/// ```
///
/// # Custom Config (orphan rule dodge)
///
/// ```rust
/// # use irys::*;
/// struct MyConfig;
/// struct MyEvent;
/// impl_reflectable!(MyEvent, { config: MyConfig });
/// ```
///
/// # Custom Registries
///
/// ```rust
/// # use irys::*;
/// # struct CoreReg;
/// # struct ObsReg;
/// struct MyEvent;
/// impl_reflectable!(MyEvent, {
///     registries: [
///         { registry: CoreReg, slots: 0..5 },
///         { registry: ObsReg, slots: 0..3 },
///     ]
/// });
/// ```
///
/// # Custom Config + Custom Registries
///
/// ```rust
/// # use irys::*;
/// # struct MyRegistry;
/// struct MyConfig;
/// struct MyEvent;
/// impl_reflectable!(MyEvent, {
///     config: MyConfig,
///     registries: [{ registry: MyRegistry, slots: 0..10 }],
/// });
/// ```
///
/// # Generic Types
///
/// ```rust
/// # use irys::*;
/// # use std::marker::PhantomData;
/// struct Wrapper<T, M> { data: T, _marker: PhantomData<M> }
///
/// // Keep M generic, pin T to String
/// impl_reflectable!(Wrapper<String, M>, {
///     generics: [M: Send + Sync + 'static],
/// });
/// ```
///
/// # Generic Types with Where Clause
///
/// ```rust
/// # use irys::*;
/// struct Container<T> { data: T }
///
/// impl_reflectable!(Container<T>, {
///     generics: [T: Send + Sync + 'static],
///     where: [T: Clone],
/// });
/// ```
#[macro_export]
macro_rules! impl_reflectable {
    ($ty:ty) => {
        $crate::__impl_reflectable_emit! {
            @ty [$ty]
            @config [$crate::DefaultConfig]
            @registries [{ registry: $crate::DefaultRegistry, slots: 0..256 }]
            @generics []
            @where []
        }
    };
    ($ty:ty, { $($fields:tt)* }) => {
        $crate::__impl_reflectable_parse! {
            @ty [$ty]
            @config [$crate::DefaultConfig]
            @registries [{ registry: $crate::DefaultRegistry, slots: 0..256 }]
            @generics []
            @where []
            @rest [$($fields)*]
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __impl_reflectable_parse {
    // Terminal: no more fields
    (@ty $ty:tt @config $config:tt @registries $reg:tt @generics $gen:tt @where $wh:tt
     @rest []) => {
        $crate::__impl_reflectable_emit! { @ty $ty @config $config @registries $reg @generics $gen @where $wh }
    };

    // Peel: config
    (@ty $ty:tt @config $_config:tt @registries $reg:tt @generics $gen:tt @where $wh:tt
     @rest [config: $config:ty, $($rest:tt)*]) => {
        $crate::__impl_reflectable_parse! { @ty $ty @config [$config] @registries $reg @generics $gen @where $wh @rest [$($rest)*] }
    };
    (@ty $ty:tt @config $_config:tt @registries $reg:tt @generics $gen:tt @where $wh:tt
     @rest [config: $config:ty]) => {
        $crate::__impl_reflectable_parse! { @ty $ty @config [$config] @registries $reg @generics $gen @where $wh @rest [] }
    };

    // Peel: registries
    (@ty $ty:tt @config $config:tt @registries $_reg:tt @generics $gen:tt @where $wh:tt
     @rest [registries: [$($registries:tt)*], $($rest:tt)*]) => {
        $crate::__impl_reflectable_parse! { @ty $ty @config $config @registries [$($registries)*] @generics $gen @where $wh @rest [$($rest)*] }
    };
    (@ty $ty:tt @config $config:tt @registries $_reg:tt @generics $gen:tt @where $wh:tt
     @rest [registries: [$($registries:tt)*]]) => {
        $crate::__impl_reflectable_parse! { @ty $ty @config $config @registries [$($registries)*] @generics $gen @where $wh @rest [] }
    };

    // Peel: generics
    (@ty $ty:tt @config $config:tt @registries $reg:tt @generics $_gen:tt @where $wh:tt
     @rest [generics: [$($generics:tt)*], $($rest:tt)*]) => {
        $crate::__impl_reflectable_parse! { @ty $ty @config $config @registries $reg @generics [$($generics)*] @where $wh @rest [$($rest)*] }
    };
    (@ty $ty:tt @config $config:tt @registries $reg:tt @generics $_gen:tt @where $wh:tt
     @rest [generics: [$($generics:tt)*]]) => {
        $crate::__impl_reflectable_parse! { @ty $ty @config $config @registries $reg @generics [$($generics)*] @where $wh @rest [] }
    };

    // Peel: where
    (@ty $ty:tt @config $config:tt @registries $reg:tt @generics $gen:tt @where $_wh:tt
     @rest [where: [$($wh:tt)*], $($rest:tt)*]) => {
        $crate::__impl_reflectable_parse! { @ty $ty @config $config @registries $reg @generics $gen @where [$($wh)*] @rest [$($rest)*] }
    };
    (@ty $ty:tt @config $config:tt @registries $reg:tt @generics $gen:tt @where $_wh:tt
     @rest [where: [$($wh:tt)*]]) => {
        $crate::__impl_reflectable_parse! { @ty $ty @config $config @registries $reg @generics $gen @where [$($wh)*] @rest [] }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __impl_reflectable_emit {
    (@ty [$ty:ty] @config [$config:ty] @registries [$($registries:tt)*] @generics [$($generics:tt)*] @where [$($wh:tt)*]) => {
        impl<$($generics)*> $crate::Reflectable<$config> for $ty
        where $($wh)*
        {
            fn reflect(self) -> $crate::Envelope {
                $crate::reflect!(self, [$($registries)*])
            }
            fn reflect_ref(&self) -> $crate::EnvelopeRef<'_> {
                $crate::reflect_ref!(&*self, [$($registries)*])
            }
            fn reflect_mut(&mut self) -> $crate::EnvelopeMut<'_> {
                $crate::reflect_mut!(&mut *self, [$($registries)*])
            }
        }
    };
}

#[doc(hidden)]
pub struct Probe<'a, T, Registry, const N: u64>(pub &'a T, PhantomData<Registry>);

impl<'a, T, R, const N: u64> Probe<'a, T, R, N> {
    #[inline(always)]
    pub fn new(val: &'a T) -> Self {
        Self(val, PhantomData)
    }
}

#[doc(hidden)]
pub trait HasCap<Marker, Registry, const N: u64> {
    fn probe(&self, caps: &mut CapabilityMap);
}

#[doc(hidden)]
pub trait NoCap<Registry, const N: u64> {
    fn probe(&self, _caps: &mut CapabilityMap) {}
}

impl<T, R, const N: u64> NoCap<R, N> for &Probe<'_, T, R, N> {}

#[doc(hidden)]
#[macro_export]
macro_rules! probe_slot {
    ($msg:expr, $caps:expr, $registry:ty, $n:literal) => {{
        use $crate::HasCap as _;
        use $crate::NoCap as _;
        (&$crate::Probe::<_, $registry, $n>::new($msg)).probe($caps);
    }};
}

/// Reflect a value, automatically detecting which capabilities it supports.
///
/// Consumes the value and returns an owned [`Envelope`].
///
/// # Basic Usage
///
/// ```rust
/// # use irys::*;
/// # use std::fmt;
/// # struct DisplayCap;
/// # impl Capability for DisplayCap { type Handle = dyn fmt::Display; }
/// # register_capability! { slot: 0, cap: DisplayCap, trait_bound: fmt::Display }
/// // Probes DefaultRegistry, slots 0..256
/// let envelope = reflect!(42i32);
/// assert!(envelope.has::<DisplayCap>());
/// ```
///
/// # Custom Registries & Ranges
///
/// ```rust
/// # use irys::*;
/// # struct MyRegistry;
/// # let value = 42i32;
/// let envelope = reflect!(value, [
///     { registry: MyRegistry, slots: 0..10 },
/// ]);
/// ```
///
/// # Multiple Registries
///
/// ```rust
/// # use irys::*;
/// # struct CoreReg;
/// # struct ObsReg;
/// # let value = 42i32;
/// let envelope = reflect!(value, [
///     { registry: CoreReg, slots: 0..5 },
///     { registry: ObsReg, slots: 0..3 },
/// ]);
/// ```
///
/// Registries probed later override earlier ones for the same capability (last-write-wins).
#[macro_export]
macro_rules! reflect {
    ($($args:tt)*) => { $crate::__reflect_internal!(@owned $($args)*) };
}

/// Reflect a shared reference, detecting capabilities without consuming the value.
///
/// Returns an [`EnvelopeRef`] with read-only access to capabilities.
/// The original value remains available after the call.
///
/// # Example
///
/// ```rust
/// # use irys::*;
/// # use std::fmt;
/// # struct DisplayCap;
/// # impl Capability for DisplayCap { type Handle = dyn fmt::Display; }
/// # register_capability! { slot: 0, cap: DisplayCap, trait_bound: fmt::Display }
/// let value = 42i32;
/// let envelope_ref = reflect_ref!(&value);
/// assert!(envelope_ref.has::<DisplayCap>());
/// assert_eq!(value, 42); // value is still usable
/// ```
#[macro_export]
macro_rules! reflect_ref {
    ($($args:tt)*) => { $crate::__reflect_internal!(@ref $($args)*) };
}

/// Reflect a mutable reference, detecting capabilities with mutable access.
///
/// Returns an [`EnvelopeMut`] with read + write access to capabilities.
/// The original value remains available after the envelope is dropped.
///
/// # Example
///
/// ```rust
/// # use irys::*;
/// # trait Resettable { fn reset(&mut self); }
/// # struct ResettableCap;
/// # impl Capability for ResettableCap { type Handle = dyn Resettable; }
/// # register_capability! { slot: 0, cap: ResettableCap, trait_bound: Resettable }
/// # struct Counter { count: u32 }
/// # impl Resettable for Counter { fn reset(&mut self) { self.count = 0; } }
/// let mut value = Counter { count: 99 };
/// {
///     let mut envelope_mut = reflect_mut!(&mut value);
///     envelope_mut.get_mut::<ResettableCap>().unwrap().reset();
/// }
/// assert_eq!(value.count, 0);
/// ```
#[macro_export]
macro_rules! reflect_mut {
    ($($args:tt)*) => { $crate::__reflect_internal!(@mut $($args)*) };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __reflect_internal {
    // === Explicit registries — normalize binding, then probe + finish ===
    (@owned $msg:expr, [$($registries:tt)*]) => {{
        let msg = $msg;
        $crate::__reflect_core!(@owned, msg, &msg, [$($registries)*])
    }};
    (@ref & $msg:expr, [$($registries:tt)*]) => {{
        let msg = &$msg;
        $crate::__reflect_core!(@ref, msg, msg, [$($registries)*])
    }};
    (@mut &mut $msg:expr, [$($registries:tt)*]) => {{
        let msg = &mut $msg;
        $crate::__reflect_core!(@mut, msg, &*msg, [$($registries)*])
    }};

    // === No registries specified — default registry fallback ===
    (@owned $msg:expr) => {
        $crate::__reflect_internal!(@owned $msg, [{ registry: $crate::DefaultRegistry, slots: 0..256 }])
    };
    (@ref & $msg:expr) => {
        $crate::__reflect_internal!(@ref & $msg, [{ registry: $crate::DefaultRegistry, slots: 0..256 }])
    };
    (@mut &mut $msg:expr) => {
        $crate::__reflect_internal!(@mut &mut $msg, [{ registry: $crate::DefaultRegistry, slots: 0..256 }])
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __reflect_core {
    (@$mode:ident, $msg:ident, $probe:expr, [$({ registry: $registry:ty, slots: $start:literal..$end:literal }),* $(,)?]) => {{
        let mut caps = $crate::CapabilityMap::new();
        $( $crate::seq!(N in $start..$end { $crate::probe_slot!($probe, &mut caps, $registry, N); }); )*
        $crate::__reflect_finish!(@$mode $msg, caps)
    }};
}

#[doc(hidden)]
#[macro_export]
macro_rules! __reflect_finish {
    (@owned $msg:ident, $caps:ident) => {
        $crate::Envelope::from_parts($msg, $caps)
    };
    (@ref $msg:ident, $caps:ident) => {
        $crate::EnvelopeRef::from_parts($msg as &dyn std::any::Any, $caps)
    };
    (@mut $msg:ident, $caps:ident) => {
        $crate::EnvelopeMut::from_parts($msg as &mut dyn std::any::Any, $caps)
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __reflect_probe {
    ($msg:expr, [$({ registry: $registry:ty, slots: $start:literal..$end:literal }),* $(,)?]) => {{
        let mut caps = $crate::CapabilityMap::new();
        $(
            $crate::seq!(N in $start..$end {
                $crate::probe_slot!($msg, &mut caps, $registry, N);
            });
        )*
        caps
    }};
}

/// Register a capability so that [`reflect!`] can detect it on any type satisfying the trait bound.
///
/// This is a **blanket registration** — it applies to ALL types that implement the given trait,
/// not just one specific type. Register once, works everywhere.
///
/// Fields can be provided in **any order**. The `registry` field is optional (defaults to
/// [`DefaultRegistry`]).
///
/// # Basic Usage (DefaultRegistry)
///
/// ```rust
/// # use irys::*;
/// # use std::fmt;
/// struct DisplayCap;
/// impl Capability for DisplayCap {
///     type Handle = dyn fmt::Display;
/// }
///
/// register_capability! {
///     slot: 0,
///     cap: DisplayCap,
///     trait_bound: fmt::Display,
/// }
/// ```
///
/// # Custom Registry
///
/// ```rust
/// # use irys::*;
/// # use std::fmt;
/// struct MyRegistry;
///
/// # struct DebugCap;
/// # impl Capability for DebugCap { type Handle = dyn fmt::Debug; }
/// register_capability! {
///     registry: MyRegistry,
///     slot: 0,
///     cap: DebugCap,
///     trait_bound: fmt::Debug,
/// }
/// ```
///
/// # Compound Trait Bounds
///
/// ```rust
/// # use irys::*;
/// # use std::fmt;
/// # struct SendDebugCap;
/// # impl Capability for SendDebugCap { type Handle = dyn fmt::Debug + Send + Sync; }
/// register_capability! {
///     slot: 0,
///     cap: SendDebugCap,
///     trait_bound: fmt::Debug + Send + Sync,
/// }
/// ```
///
/// # Any Field Order
///
/// ```rust
/// # use irys::*;
/// # use std::fmt;
/// # struct DebugCap;
/// # impl Capability for DebugCap { type Handle = dyn fmt::Debug; }
/// register_capability! {
///     trait_bound: fmt::Debug,
///     cap: DebugCap,
///     slot: 0,
/// }
/// ```
///
/// # Slot Collisions
///
/// Two capabilities at the same slot in the same registry will produce a **compile error**
/// (duplicate inherent method). This is intentional — it prevents silent conflicts.
#[macro_export]
macro_rules! register_capability {
    ($($input:tt)*) => {
        $crate::__register_cap_parse! { [] @rest [$($input)*] }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __register_cap_parse {
    // === Terminal: no more tokens ===
    ([$($parsed:tt)*] @rest []) => {
        $crate::__register_cap_emit! { $($parsed)* }
    };

    // Peel: registry
    ([$($parsed:tt)*] @rest [registry: $registry:ty, $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @registry [$registry]] @rest [$($rest)*] }
    };

    // Peel: slot
    ([$($parsed:tt)*] @rest [slot: $slot:literal, $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @slot [$slot]] @rest [$($rest)*] }
    };

    // Peel: cap
    ([$($parsed:tt)*] @rest [cap: $cap:ty, $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @cap [$cap]] @rest [$($rest)*] }
    };

    // Peel: generics (bracketed group)
    ([$($parsed:tt)*] @rest [generics: $generics:tt, $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @generics $generics] @rest [$($rest)*] }
    };

    // Peel: where (bracketed group)
    ([$($parsed:tt)*] @rest [where: $wh:tt, $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @where $wh] @rest [$($rest)*] }
    };

    // Peel: trait_bound (freeform — munch until next keyword)
    ([$($parsed:tt)*] @rest [trait_bound: $($rest:tt)+]) => {
        $crate::__register_cap_munch! { @target trait_bound @parsed [$($parsed)*] @accum [] @rest [$($rest)+] }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __register_cap_munch {
    // Hit ", <keyword>:" — done, store and continue
    (@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [, registry: $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [registry: $($rest)*] }
    };
    (@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [, slot: $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [slot: $($rest)*] }
    };
    (@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [, cap: $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [cap: $($rest)*] }
    };
    (@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [, trait_bound: $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [trait_bound: $($rest)*] }
    };
    (@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [, generics: $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [generics: $($rest)*] }
    };
    (@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [, where: $($rest:tt)*]) => {
        $crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [where: $($rest)*] }
    };

    // End of input
    (@target $target:ident @parsed [$($parsed:tt)*] @accum [$($accum:tt)*] @rest [$(,)?]) => {
        $crate::__register_cap_parse! { [$($parsed)* @$target [$($accum)*]] @rest [] }
    };

    // Munch one token
    (@target $target:ident @parsed $parsed:tt @accum [$($accum:tt)*] @rest [$first:tt $($rest:tt)*]) => {
        $crate::__register_cap_munch! { @target $target @parsed $parsed @accum [$($accum)* $first] @rest [$($rest)*] }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __register_cap_emit {
    ($($input:tt)*) => {
        $crate::__register_cap_norm! {
            @registry [] @slot [] @cap [] @trait_bound [] @generics [] @where []
            @input [$($input)*]
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __register_cap_norm {
    // Terminal — all input consumed, emit
    (@registry [$($registry:tt)*] @slot [$($slot:tt)+] @cap [$($cap:tt)+] @trait_bound [$($tb:tt)+] @generics [$($gen:tt)*] @where [$($wh:tt)*]
     @input []) => {
        $crate::__register_cap_final! { @registry [$($registry)*] @slot [$($slot)+] @cap [$($cap)+] @trait_bound [$($tb)+] @generics [$($gen)*] @where [$($wh)*] }
    };

    // Extract each @key [value] pair
    (@registry $r:tt @slot $s:tt @cap $c:tt @trait_bound $tb:tt @generics $g:tt @where $w:tt
     @input [@registry [$($registry:tt)*] $($rest:tt)*]) => {
        $crate::__register_cap_norm! { @registry [$($registry)*] @slot $s @cap $c @trait_bound $tb @generics $g @where $w @input [$($rest)*] }
    };
    (@registry $r:tt @slot $s:tt @cap $c:tt @trait_bound $tb:tt @generics $g:tt @where $w:tt
     @input [@slot [$($slot:tt)*] $($rest:tt)*]) => {
        $crate::__register_cap_norm! { @registry $r @slot [$($slot)*] @cap $c @trait_bound $tb @generics $g @where $w @input [$($rest)*] }
    };
    (@registry $r:tt @slot $s:tt @cap $c:tt @trait_bound $tb:tt @generics $g:tt @where $w:tt
     @input [@cap [$($cap:tt)*] $($rest:tt)*]) => {
        $crate::__register_cap_norm! { @registry $r @slot $s @cap [$($cap)*] @trait_bound $tb @generics $g @where $w @input [$($rest)*] }
    };
    (@registry $r:tt @slot $s:tt @cap $c:tt @trait_bound $tb:tt @generics $g:tt @where $w:tt
     @input [@trait_bound [$($bound:tt)*] $($rest:tt)*]) => {
        $crate::__register_cap_norm! { @registry $r @slot $s @cap $c @trait_bound [$($bound)*] @generics $g @where $w @input [$($rest)*] }
    };
    (@registry $r:tt @slot $s:tt @cap $c:tt @trait_bound $tb:tt @generics $g:tt @where $w:tt
     @input [@generics [$($gen:tt)*] $($rest:tt)*]) => {
        $crate::__register_cap_norm! { @registry $r @slot $s @cap $c @trait_bound $tb @generics [$($gen)*] @where $w @input [$($rest)*] }
    };
    (@registry $r:tt @slot $s:tt @cap $c:tt @trait_bound $tb:tt @generics $g:tt @where $w:tt
     @input [@where [$($wh:tt)*] $($rest:tt)*]) => {
        $crate::__register_cap_norm! { @registry $r @slot $s @cap $c @trait_bound $tb @generics $g @where [$($wh)*] @input [$($rest)*] }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __register_cap_final {
    // No registry — use default, forward
    (@registry [] @slot $s:tt @cap $c:tt @trait_bound $tb:tt @generics $g:tt @where $w:tt) => {
        $crate::__register_cap_final! { @registry [$crate::DefaultRegistry] @slot $s @cap $c @trait_bound $tb @generics $g @where $w }
    };
    (@registry [$registry:ty] @slot [$slot:literal] @cap [$cap:ty] @trait_bound [$($bounds:tt)+] @generics [$($generics:tt)*] @where [$($wh:tt)*]) => {
        impl<'a, __ProbeTarget: $($bounds)+ + 'static, $($generics)*> $crate::HasCap<$cap, $registry, $slot>
            for $crate::Probe<'a, __ProbeTarget, $registry, $slot>
        where $($wh)*
        {
            fn probe(&self, caps: &mut $crate::CapabilityMap) {
                caps.insert_cast::<$cap>(
                    |any| {
                        let val = any.downcast_ref::<__ProbeTarget>()?;
                        Some(val as &<$cap as $crate::Capability>::Handle)
                    },
                    |any| {
                        let val = any.downcast_mut::<__ProbeTarget>()?;
                        Some(val as &mut <$cap as $crate::Capability>::Handle)
                    },
                );
            }
        }
    };
}
