named_generics_bundle/_lib.rs
1//! [`named_generics_bundle`]: `named_generics_bundle`
2#![doc = include_str!("../README.md")]
3#![no_std]
4#![forbid(unsafe_code)]
5#![allow(unused_braces)]
6
7/// Main macro, entrypoint to the features of the crate.
8///
9/// See the [main-level docs][`crate`] for more contextual information about this attribute.
10///
11/// # Usage
12///
13/// Basic:
14///
15/// ```rust
16/// # use ::named_generics_bundle::named_generics_bundle;
17/// # use Sized as SomeBounds;
18/// #
19/// #[named_generics_bundle]
20/// trait SomeTrait {
21/// type SomeAssocType: SomeBounds + Clone;
22/// }
23///
24/// fn some_api<S: SomeTrait>(nameable: S::SomeAssocType) {
25/// // Properly implied bounds.
26/// nameable.clone();
27/// }
28///
29/// /// We shall have `Example: SomeTrait + Sized + AllStdDeriveTraits`
30/// type Example = SomeTrait![
31/// # SomeAssocType = (), /*
32/// SomeAssocType = ...,
33/// # */
34/// ];
35///
36/// some_api::<Example>(
37/// // …,
38/// # (),
39/// );
40/// // or, directly:
41/// some_api::<SomeTrait![SomeAssocType = i32]>(42);
42/// ```
43///
44/// More precisely, regarding the attribute macro invocation:
45///
46/// <details open class="custom"><summary><span class="summary-box"><span>Click to show</span></span></summary>
47///
48/// ```rust
49/// # () /*
50/// /// docs…
51/// #[named_generics_bundle(
52/// $(
53/// // Optional. Path must be an absolute path (leading `crate`).
54/// // It allows making the generated eponymous `SomeTrait!` macro be usable
55/// // anywhere, that is, without having to have `SomeTrait` in the current scope.
56/// //
57/// // The macro will tell you what to put here if you get it wrong 🤓
58/// path_to_this_very_module = crate::path::to::this::very::module,
59/// )?
60/// $(
61/// // Optional. Niche and advanced. Useful when re-exporthing this macro from
62/// // another crate (e.g. through some `#[macro_export]`ed macro).
63/// path_to_named_generics_bundle_crate = ::my_crate::reexports::named_generics_bundle,
64/// )?
65/// )]
66/// $pub:vis
67/// trait SomeTrait $(: 'static)? {
68/// $(
69/// /// docs…
70/// type $EachAssocType:ident $(: $TraitBounds…)?;
71/// )*
72/// }
73/// # */
74/// ```
75///
76/// </details>
77///
78/// # Features
79///
80/// <details open class="custom"><summary><span class="summary-box"><span>Click to hide</span></span></summary>
81///
82/// - ### `MyBundle!` eponymous macro definition
83///
84/// The main point of this all is the definition of the convenience `Eponymous!` macro alongside
85/// the trait definition:
86///
87/// ```rust
88/// #[::named_generics_bundle::named_generics_bundle]
89/// trait MyBundle {
90/// type Foo;
91/// // …
92/// }
93///
94/// // defines an eponymous "type-level-instantiation" macro.
95/// # type Example =
96/// MyBundle![
97/// Foo = i32,
98/// // …
99/// ]
100/// # ;
101/// ```
102///
103/// - ### The `trait` definition remains `dyn`-compatible.
104///
105/// As a matter of fact, this is how the generated `Eponymous![]` macro works under the hood:
106///
107/// ```rust
108/// # () /*
109/// AnnotatedTrait![ A = B, C = D, … ]
110/// // expands to:
111/// PhantomData::<fn(ඞ<()>) -> dyn AnnotatedTrait<ඞ<()>, A = B, C = D, …>>
112/// # */
113/// ```
114///
115/// - Add to this a trivial blanket impl of `AnnotatedTrait` for
116/// `PhantomData<fn(ඞ<()>) -> impl ?Sized + AnnotatedTrait<ඞ<()>>>`, and _voilà_!
117///
118/// In case the `ඞ<…>` wrapper did not give this away, do note that the precise form of this
119/// expansion is **not** guaranteed, and therefore susceptible to change within non-major Semver
120/// bumps, as **it will not be considered a breaking change**: the disclosure of this expansion
121/// is done merely for educational/informative reasons.
122///
123/// - ### Implied Bounds (`Sized + Copy + Clone + Send/Sync + …`)
124///
125/// `T : AnnotatedTrait` entails not only `: Sized`, but also every
126/// stdlib `#[derive()]` trait, for convenient use with such (dumb) derives.
127///
128/// More precisely, using an advanced trick with
129/// [`::implied_bounds`](https://docs.rs/implied_bounds), the macro makes it so the `dyn`-safe
130/// `trait` nonetheless entails the following:
131///
132/// ```rust
133/// # () /*
134/// T : AnnotatedTrait,
135/// // to entail:
136/// T :
137/// Debug +
138/// Copy + // and thus, `Clone`
139/// Default +
140/// Ord + // and thus, `PartialOrd + Eq + PartialEq`,
141/// Hash +
142/// Send + Sync + Unpin +
143/// ,
144/// # */
145/// ```
146///
147/// </details>
148///
149/// # Quirks
150///
151/// - To keep things simple, the attribute rejects trait with generics parameters, or associated
152/// items other than types.
153///
154/// - ## The `path_to_this_very_module = ` attribute arg
155///
156/// The generated `Eponymous!` macro, by default, needs to be in scope to be invoked.
157/// That is, invoking it through some qualified path is most likely to result in a path
158/// resolution error:
159///
160/// ```rust ,compile_fail
161/// mod some_module {
162/// #[::named_generics_bundle::named_generics_bundle]
163/// pub trait Example {}
164/// }
165///
166/// type T = some_module::Example![]; // ❌
167/// #
168/// # fn main() {}
169/// ```
170///
171/// which fails with:
172///
173/// <details class="custom"><summary><span class="summary-box"><span>Click to show</span></span></summary>
174///
175/// ```rust ,ignore
176/// # () /*
177/// error[E0405]: cannot find trait `Example` in this scope
178/// --> src/_lib.rs:185:15
179/// |
180/// 7 | pub trait Example {}
181/// | ^^^^^^^ not found in this scope
182/// ...
183/// 10 | type T = some_module::Example![]; // ❌
184/// | ----------------------- in this macro invocation
185/// |
186/// = note: this error originates in the macro `some_module::Example` (in Nightly builds, run with -Z macro-backtrace for more info)
187/// # */
188/// ```
189///
190/// </details>
191///
192/// This is not a deliberate choice, but a limitation of the language, wherein a macro
193/// invocation such as that of [`#[named_generics_bundle]`][`named_generics_bundle] is unable to know the full/absolute
194/// [`module_path!()`] whence it has been invoked; and yet such a path would be useful or
195/// even necessary to make an invocation like `some_module::Example![…]` robust.
196///
197/// Indeed, the invocation of `Example![…]` will want to involve, and name, `dyn Example`.
198///
199/// - Either the macro and/or the trait is in scope, and doing `dyn Example` will Just Work™.
200///
201/// This is the usual, happy-case case/scenario.
202///
203/// - Or it won't be in scope, like in this instance, and using a more qualified path, such
204/// as `dyn crate::some_module::Example`, is necessary.
205///
206/// Hence the "need" for the invoker of the attribute macro to provide this `crate::some_module`
207/// information to the macro, which is to be done _via_ the `path_to_this_very_module =`
208/// attribute arg:
209///
210/// ```rust
211/// pub mod some_module {
212/// #[::named_generics_bundle::named_generics_bundle(
213/// path_to_this_very_module = crate::some_module,
214/// )]
215/// pub trait Example {}
216/// }
217///
218/// type T = some_module::Example![]; // ✅
219/// #
220/// # fn main() {}
221/// ```
222///
223/// - Note: [`#[named_generics_bundle]`][`named_generics_bundle] will replace the `crate::`
224/// part of this specifier with `$crate::` so as to make the `Example![]` macro it
225/// generates, resilient to being used across crates / from a downstream dependent crate.
226///
227/// - ## The `path_to_named_generics_bundle_crate = ` attribute arg
228///
229/// Since this macro stems from a `proc-macro = true` backend using a frontend/façade package,
230/// the attribute is unable to have a 100%-resilient way to name, and refer back to, its own
231/// frontend crate items. So unless told how, the attribute has no choice but to assume that
232/// users of the attribute will be direct dependents of `::named_generics_bundle`, resulting in
233/// the expansion involving then some hard-coded `::named_generics_bundle`-prefixes.
234///
235/// This is usally fine, but for the case of a _non-direct_ downstream dependent (which is kind
236/// of the case if a direct dependent `#[macro_export]`s some of our functionality to _deeper_,
237/// non-direct, dependents).
238///
239/// At this point, some re-export of this `::named_generics_bundle` crate must have proven
240/// necessary, from somehere. This is the path to be providing to this attribute args.
241///
242/// ```rust
243/// # pub extern crate named_generics_bundle;
244/// #
245/// #[doc(hidden)] /** Not part of the public API */ pub
246/// mod __internals {
247/// /// 👇 Notice whence (and how) `::named_generics_bundle` is being reëxported
248/// pub use ::named_generics_bundle as nmb;
249/// }
250///
251/// /// Demo
252/// /// ```rust
253/// /// ::your_crate::my_fancy_macro!(); // It Works!
254/// /// ```
255/// #[macro_export]
256/// macro_rules! my_fancy_macro {( ... ) => (
257/// #[$crate::__internals::nmb::named_generics_bundle(
258/// path_to_named_generics_bundle_crate = $crate::__internals::nmb,
259/// )]
260/// trait SomeTrait {
261/// ...
262/// }
263/// )}
264/// #
265/// # fn main() {}
266/// ```
267///
268pub use ::named_generics_bundle_proc_macros::named_generics_bundle;
269
270// macro internals
271#[doc(hidden)] /** Not part of the public API */ pub
272mod ඞ {
273 pub use ::core::{
274 self,
275 cmp::Ord,
276 default::Default,
277 fmt::Debug,
278 hash::Hash,
279 marker::{Copy, Send, Sync, Unpin},
280 };
281 pub use ::implied_bounds::ImpliedPredicate;
282 pub use crate::{
283 const_helpers::*,
284 };
285
286 /// This type is used to convey the notion that users of this attribute are
287 /// not to rely on the blanket impl of:
288 /// `impl Trait for PhantomData<fn() -> ඞ<impl ?Sized + Trait<()>>>`
289 ///
290 /// It effectively is, currently, just an identity type wrapper, but it shall make coherence
291 /// treat the resulting type as being literally any possible type, thereby reducing the risk
292 /// of "breaking changes" should I decide to change what the `Eponymous![]` macro unsugars to.
293 pub type ඞ<T> = <T as Identity>::ItSelf;
294
295 pub trait Identity { type ItSelf : ?Sized; }
296 impl<T : ?Sized> Identity for T { type ItSelf = Self; }
297}
298
299mod const_helpers;
300
301#[doc = include_str!("compile_fail_tests.md")]
302mod _compile_fail_tests {}
303
304#[cfg(any(test, feature = "__internal_testing"))]
305extern crate self as named_generics_bundle;
306
307#[cfg(any(test, feature = "__internal_testing"))]
308pub mod tests;