#[named_generics_bundle]Expand description
Main macro, entrypoint to the features of the crate.
See the main-level docs for more contextual information about this attribute.
§Usage
Basic:
#[named_generics_bundle]
trait SomeTrait {
type SomeAssocType: SomeBounds + Clone;
}
fn some_api<S: SomeTrait>(nameable: S::SomeAssocType) {
// Properly implied bounds.
nameable.clone();
}
/// We shall have `Example: SomeTrait + Sized + AllStdDeriveTraits`
type Example = SomeTrait![
SomeAssocType = ...,
];
some_api::<Example>(
// …,
);
// or, directly:
some_api::<SomeTrait![SomeAssocType = i32]>(42);More precisely, regarding the attribute macro invocation:
Click to show
/// docs…
#[named_generics_bundle(
$(
// Optional. Path must be an absolute path (leading `crate`).
// It allows making the generated eponymous `SomeTrait!` macro be usable
// anywhere, that is, without having to have `SomeTrait` in the current scope.
//
// The macro will tell you what to put here if you get it wrong 🤓
path_to_this_very_module = crate::path::to::this::very::module,
)?
$(
// Optional. Niche and advanced. Useful when re-exporthing this macro from
// another crate (e.g. through some `#[macro_export]`ed macro).
path_to_named_generics_bundle_crate = ::my_crate::reexports::named_generics_bundle,
)?
)]
$pub:vis
trait SomeTrait $(: 'static)? {
$(
/// docs…
type $EachAssocType:ident $(: $TraitBounds…)?;
)*
}§Features
Click to hide
§
MyBundle!eponymous macro definitionThe main point of this all is the definition of the convenience
Eponymous!macro alongside the trait definition:#[::named_generics_bundle::named_generics_bundle] trait MyBundle { type Foo; // … } // defines an eponymous "type-level-instantiation" macro. MyBundle![ Foo = i32, // … ]§The
traitdefinition remainsdyn-compatible.As a matter of fact, this is how the generated
Eponymous![]macro works under the hood:AnnotatedTrait![ A = B, C = D, … ] // expands to: PhantomData::<fn(ඞ<()>) -> dyn AnnotatedTrait<ඞ<()>, A = B, C = D, …>>- Add to this a trivial blanket impl of
AnnotatedTraitforPhantomData<fn(ඞ<()>) -> impl ?Sized + AnnotatedTrait<ඞ<()>>>, and voilà!
In case the
ඞ<…>wrapper did not give this away, do note that the precise form of this expansion is not guaranteed, and therefore susceptible to change within non-major Semver bumps, as it will not be considered a breaking change: the disclosure of this expansion is done merely for educational/informative reasons.- Add to this a trivial blanket impl of
§Implied Bounds (
Sized + Copy + Clone + Send/Sync + …)T : AnnotatedTraitentails not only: Sized, but also every stdlib#[derive()]trait, for convenient use with such (dumb) derives.More precisely, using an advanced trick with
::implied_bounds, the macro makes it so thedyn-safetraitnonetheless entails the following:T : AnnotatedTrait, // to entail: T : Debug + Copy + // and thus, `Clone` Default + Ord + // and thus, `PartialOrd + Eq + PartialEq`, Hash + Send + Sync + Unpin + ,
§Quirks
-
To keep things simple, the attribute rejects trait with generics parameters, or associated items other than types.
§The
path_to_this_very_module =attribute argThe generated
Eponymous!macro, by default, needs to be in scope to be invoked. That is, invoking it through some qualified path is most likely to result in a path resolution error:ⓘmod some_module { #[::named_generics_bundle::named_generics_bundle] pub trait Example {} } type T = some_module::Example![]; // ❌which fails with:
Click to show
ⓘerror[E0405]: cannot find trait `Example` in this scope --> src/_lib.rs:185:15 | 7 | pub trait Example {} | ^^^^^^^ not found in this scope ... 10 | type T = some_module::Example![]; // ❌ | ----------------------- in this macro invocation | = note: this error originates in the macro `some_module::Example` (in Nightly builds, run with -Z macro-backtrace for more info)This is not a deliberate choice, but a limitation of the language, wherein a macro invocation such as that of
#[named_generics_bundle]is unable to know the full/absolutemodule_path!()whence it has been invoked; and yet such a path would be useful or even necessary to make an invocation likesome_module::Example![…]robust.Indeed, the invocation of
Example![…]will want to involve, and name,dyn Example.-
Either the macro and/or the trait is in scope, and doing
dyn Examplewill Just Work™.This is the usual, happy-case case/scenario.
-
Or it won’t be in scope, like in this instance, and using a more qualified path, such as
dyn crate::some_module::Example, is necessary.
Hence the “need” for the invoker of the attribute macro to provide this
crate::some_moduleinformation to the macro, which is to be done via thepath_to_this_very_module =attribute arg:pub mod some_module { #[::named_generics_bundle::named_generics_bundle( path_to_this_very_module = crate::some_module, )] pub trait Example {} } type T = some_module::Example![]; // ✅- Note:
#[named_generics_bundle]will replace thecrate::part of this specifier with$crate::so as to make theExample![]macro it generates, resilient to being used across crates / from a downstream dependent crate.
-
§The
path_to_named_generics_bundle_crate =attribute argSince this macro stems from a
proc-macro = truebackend using a frontend/façade package, the attribute is unable to have a 100%-resilient way to name, and refer back to, its own frontend crate items. So unless told how, the attribute has no choice but to assume that users of the attribute will be direct dependents of::named_generics_bundle, resulting in the expansion involving then some hard-coded::named_generics_bundle-prefixes.This is usally fine, but for the case of a non-direct downstream dependent (which is kind of the case if a direct dependent
#[macro_export]s some of our functionality to deeper, non-direct, dependents).At this point, some re-export of this
::named_generics_bundlecrate must have proven necessary, from somehere. This is the path to be providing to this attribute args.#[doc(hidden)] /** Not part of the public API */ pub mod __internals { /// 👇 Notice whence (and how) `::named_generics_bundle` is being reëxported pub use ::named_generics_bundle as nmb; } /// Demo /// ```rust /// ::your_crate::my_fancy_macro!(); // It Works! /// ``` #[macro_export] macro_rules! my_fancy_macro {( ... ) => ( #[$crate::__internals::nmb::named_generics_bundle( path_to_named_generics_bundle_crate = $crate::__internals::nmb, )] trait SomeTrait { ... } )}