implied_bounds/_lib.rs
1//! [`implied_bounds`]: `implied_bounds`
2//! [`ImpliedPredicate`]: `ImpliedPredicate`
3#![doc = include_str!("../README.md")]
4#![no_std]
5#![forbid(unsafe_code)]
6#![allow(unused_braces)]
7#![doc(html_logo_url = "https://gist.github.com/user-attachments/assets/528cd8ea-f954-434c-a7f2-6147e82cc10b")]
8#![cfg_attr(feature = "better-docs", feature(doc_cfg))]
9
10
11pub use helper_trait::ImpliedPredicate;
12mod helper_trait;
13
14/// Convenience attribute macro to help one rewrite a `trait` definition as per the rules described
15/// in the documentation of [`ImpliedPredicate`].
16///
17/// Indeed, that trait is very handy, but its usage is not only not the most obvious to write, but
18/// more importantly, not very readable afterwards.
19///
20/// Since it is actually a very mechanical operation, it is a good fit for macro automation 🙂
21///
22/// ## Example
23///
24/// The following fails to compile:
25///
26/// ```rust ,compile_fail
27/// trait Trait<U: Clone>
28/// where
29/// Self::Gat<true>: Send,
30/// {
31/// type Gat<const IS_SEND: bool>;
32/// }
33///
34/// fn demo<T: Trait<U>, U>()
35/// where
36/// // ❌ Error, missing:
37/// // U: Clone,
38/// // T::Gat<true>: Send,
39/// {}
40/// ```
41///
42/// - Error message:
43///
44/// <details class="custom"><summary><span class="summary-box"><span>Click to show</span></span></summary>
45///
46/// ```rust ,ignore
47/// # /*
48/// error[E0277]: the trait bound `U: Clone` is not satisfied
49/// --> src/_lib.rs:29:12
50/// |
51/// 10 | fn demo<T: Trait<U>, U>()
52/// | ^^^^^^^^ the trait `Clone` is not implemented for `U`
53/// |
54/// note: required by a bound in `Trait`
55/// --> src/_lib.rs:22:16
56/// |
57/// 3 | trait Trait<U: Clone>
58/// | ^^^^^ required by this bound in `Trait`
59/// help: consider restricting type parameter `U`
60/// |
61/// 10 | fn demo<T: Trait<U>, U: std::clone::Clone>()
62/// | +++++++++++++++++++
63///
64/// error[E0277]: `<T as Trait<U>>::Gat<true>` cannot be sent between threads safely
65/// --> src/_lib.rs:29:12
66/// |
67/// 10 | fn demo<T: Trait<U>, U>()
68/// | ^^^^^^^^ `<T as Trait<U>>::Gat<true>` cannot be sent between threads safely
69/// |
70/// = help: the trait `Send` is not implemented for `<T as Trait<U>>::Gat<true>`
71/// note: required by a bound in `Trait`
72/// --> src/_lib.rs:24:22
73/// |
74/// 3 | trait Trait<U: Clone>
75/// | ----- required by a bound in this trait
76/// 4 | where
77/// 5 | Self::Gat<true>: Send,
78/// | ^^^^ required by this bound in `Trait`
79/// help: consider further restricting the associated type
80/// |
81/// 11 | where <T as Trait<U>>::Gat<true>: Send
82/// | ++++++++++++++++++++++++++++++++
83/// # */
84/// ```
85///
86/// </details>
87///
88/// You can easily fix this by slapping the <code>[#\[implied_bounds\]][`implied_bounds`]</code>
89/// attribute on it:
90///
91/// ```rust
92/// #[::implied_bounds::implied_bounds] // 👈
93/// trait Trait<U: Clone>
94/// where
95/// Self::Gat<true>: Send,
96/// {
97/// type Gat<const IS_SEND: bool>;
98/// }
99///
100/// fn demo<T: Trait<U>, U>()
101/// where
102/// // OK ✅
103/// {}
104/// ```
105///
106/// This shall not change anything for implementors (they have to abide by the provided
107/// bounds/clauses/predicates no matter whether the
108/// <code>[#\[implied_bounds\]][`implied_bounds`]</code> attribute is used or not, and it shall
109/// suffice).
110///
111/// ## How does the macro work
112///
113/// - Tip: you can provide the `debug` arg to the attribute for it to highlight the non-implied
114/// clauses it shall rewrite:
115///
116/// ```rust
117/// # /*
118/// // 👇
119/// #[implied_bounds(debug)]
120/// trait ...
121/// # */
122/// ```
123///
124/// The attribute identifies the non-implied clauses (bounds on generic type parameters, as well
125/// as `where` clauses where the left-hand-side (bounded type) is not `Self`), and rewrites them
126/// using [`ImpliedPredicate`], like this:
127///
128/// ```rust
129/// use ::implied_bounds::*;
130///
131/// #[implied_bounds] // 👈
132/// trait Trait<U: Clone>
133/// where
134/// Self::Gat<true>: Send,
135/// {
136/// type Gat<const IS_SEND: bool>;
137/// }
138/// ```
139///
140/// becomes:
141///
142/// ```rust
143/// use ::implied_bounds::*;
144///
145/// trait Trait<U>
146/// :
147/// ImpliedPredicate<U, Impls: Clone> +
148/// ImpliedPredicate<Self::Gat<true>, Impls: Send> +
149/// {
150/// type Gat<const IS_SEND: bool>;
151/// }
152/// ```
153///
154/// where [`ImpliedPredicate`] is a trivially-true / always-holding trait clause, on condition
155/// that it be well-formed, _i.e._, on condition that the bounds on its `Impls` associated type
156/// do hold, wherein its `Impls` associated type is defined to always be the same as the generic arg fed
157/// to it:
158///
159/// ```rust
160/// # /*
161/// X : Bounds…
162/// ⇔
163/// ImpliedPredicate<X, Impls: Bounds…>
164/// # */
165/// ```
166#[cfg(feature = "proc-macros")]
167#[cfg_attr(feature = "better-docs",
168 doc(cfg(any(feature = "default", feature = "proc-macros"))),
169)]
170pub use ::implied_bounds_proc_macros::implied_bounds;
171
172// macro internals
173#[doc(hidden)] /** Not part of the public API */ pub
174mod ඞ {
175 pub use ::core; // or `std`
176
177 /// We reëxport this, and rename it, merely so the diagnostics read a bit more nicely:
178 ///
179 /// That way we get:
180 ///
181 /// > which is required by `<Bar as implied_bounds::ඞ::ImpliedPredicate<…>`
182 ///
183 /// instead of:
184 ///
185 /// > which is required by `<Bar as implied_bounds::helper_trait::HasAssoc<…>`
186 pub use crate::helper_trait::HasAssoc as ImpliedPredicate;
187}
188
189#[doc = include_str!("compile_fail_tests.md")]
190mod _compile_fail_tests {}