#[impl_supertrait]
Expand description
Must be attached to any impl statement involving a supertrait.
This is the impl analogue of #[supertrait]
that you should use
whenever you impl a supertrait. In fact, a sealing technique is used to prevent anyone from
implementing a supertrait manually without the use of #[impl_supertrait]
, For details on
this sealing technique, see the expansion details for
#[supertrait]
.
Consider the following supertrait definition (from the docs for
#[supertrait]
):
use supertrait::*;
#[supertrait]
pub trait Fizz<T: Copy>: Copy + Sized {
type Foo = Option<T>;
type Bar;
const fn double_value(val: T) -> (T, T) {
(val, val)
}
const fn triple_value(val: T) -> (T, T, T);
fn double_self_plus(&self, plus: Self::Foo) -> (Self, Self, Self::Foo) {
(*self, *self, plus)
}
const fn interleave<I>(&self, a: T, b: I) -> (I, Self::Foo, T);
}
The following code uses #[impl_supertrait]
to implement Fizz<T>
for the struct Buzz
and makes use of the implementation in various ways:
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct Buzz;
#[impl_supertrait]
impl<T: Copy> Fizz<T> for Buzz {
type Bar = usize;
const fn triple_value(val: T) -> (T, T, T) {
(val, val, val)
}
const fn interleave<I>(&self, a: T, b: I) -> (I, Self::Foo, T) {
(b, Some(a), a)
}
}
#[test]
const fn test_buzz_const() {
assert!(Buzz::triple_value(3).0 == 3);
let buzz = Buzz {};
match buzz.interleave('h', false).1 {
Some(c) => assert!(c == 'h'),
None => unreachable!(),
}
}
#[test]
fn test_buzz_default_associated_types() {
let buzz = Buzz {};
assert_eq!(buzz.double_self_plus(Some(3)), (buzz, buzz, Some(3)))
}
Note that the Self::SomeType
syntax can be used to refer to associated types anywhere
within a #[impl_supertrait]
impl block.
§Expansion
Default associated types that are not overridden are redirected to point to their counter
parts in MyTrait::Defaults
, with any accompanying generics. Thus the proper paths of any
types mentioned in default associated types is preserved thanks to the use super::*
in
the “wormhole” MyTrait
module.
Const fns are implemented as inherents (i.e., directly implemented on the target type) because Rust does not yet support const fns as trait items in stable. This adds a few limitations, mainly around naming collisions, however all bounds and generics on const fns are preserved, and failing to implement them will likewise result in a compile error, so this is probably as close as we can get to something that emulates const fns as trait items in a somewhat usable way in stable Rust.
Here is the expansion for the above #[impl_supertrait]
:
impl<T: Copy> Fizz::Trait<T> for Buzz {
type Bar = usize;
// a value for `Foo` was not specified by the implementer, so the macro expansion
// substitutes the value for `Foo` contained in `Fizz::Defaults`, preserving
// whatever module-local types that may be mentioned in the default associated
// type.
type Foo = <Fizz::Defaults as Fizz::DefaultTypes<T, Buzz>>::Foo;
fn interleave<I>(&self, a: T, b: I) -> (I, <Buzz as Fizz::Trait<T>>::Foo, T) {
(b, Some(a), a)
}
fn triple_value(val: T) -> (T, T, T) {
(val, val, val)
}
fn double_value(val: T) -> (T, T) {
(val, val)
}
}
// This line unseals `Fizz`. Without this line, the sealing bounds on `Fizz`
// will create a compile error.
impl Fizz::SupertraitSealed3587271628 for Buzz {}
// This impl block contains the (inherent) const fn impls of `Fizz` on `Buzz`.
impl Buzz {
pub const fn interleave<I, T: Copy>(
&self,
a: T,
b: I,
) -> (I, <Buzz as Fizz::Trait<T>>::Foo, T) {
(b, Some(a), a)
}
pub const fn triple_value<T: Copy>(val: T) -> (T, T, T) {
(val, val, val)
}
pub const fn double_value<T: Copy>(val: T) -> (T, T) {
(val, val)
}
}
// This use statement is automatically inserted by the macro expansion to ensure
// the underlying trait is actually brought into scope, since because of the
// "wormhole module" pattern, it is actually within the `Fizz` module.
#[allow(unused)]
use Fizz::Trait as BuzzFizzTraitImpl_4;
See the documentation for #[supertrait]
for more information.
§Debug Mode
If you enable the debug
feature, you can add debug
as an ident argument to this
attribute macro and its expansion will be pretty-printed to the terminal at build time.
This is extremely useful for debugging supertrait
internals and for providing detailed
information when reporting bugs.