136 lines
4.0 KiB
Rust
136 lines
4.0 KiB
Rust
/// Define a trait as usual, and a macro that can be used to instantiate
|
|
/// implementations of it.
|
|
///
|
|
/// There *must* be section markers in the trait definition:
|
|
/// @section type for associated types
|
|
/// @section self for methods
|
|
/// @section nodelegate for arbitrary tail that is not forwarded.
|
|
macro_rules! trait_template {
|
|
($(#[$doc:meta])* pub trait $name:ident $($methods:tt)*) => {
|
|
macro_rules! $name {
|
|
($m:ident $extra:tt) => {
|
|
$m! {
|
|
$extra
|
|
pub trait $name $($methods)*
|
|
}
|
|
}
|
|
}
|
|
|
|
remove_sections! { []
|
|
$(#[$doc])*
|
|
pub trait $name $($methods)*
|
|
|
|
// This is where the trait definition is reproduced by the macro.
|
|
// It makes the source links point to this place!
|
|
//
|
|
// I'm sorry, you'll have to find the source by looking at the
|
|
// source of the module the trait is defined in.
|
|
//
|
|
// We use this nifty macro so that we can automatically generate
|
|
// delegation trait impls and implement the graph traits for more
|
|
// types and combinators.
|
|
}
|
|
}
|
|
}
|
|
|
|
macro_rules! remove_sections_inner {
|
|
([$($stack:tt)*]) => {
|
|
$($stack)*
|
|
};
|
|
// escape the following tt
|
|
([$($stack:tt)*] @escape $_x:tt $($t:tt)*) => {
|
|
remove_sections_inner!([$($stack)*] $($t)*);
|
|
};
|
|
([$($stack:tt)*] @section $x:ident $($t:tt)*) => {
|
|
remove_sections_inner!([$($stack)*] $($t)*);
|
|
};
|
|
([$($stack:tt)*] $t:tt $($tail:tt)*) => {
|
|
remove_sections_inner!([$($stack)* $t] $($tail)*);
|
|
};
|
|
}
|
|
|
|
// This is the outer layer, just find the { } of the actual trait definition
|
|
// recurse once into { }, but not more.
|
|
macro_rules! remove_sections {
|
|
([$($stack:tt)*]) => {
|
|
$($stack)*
|
|
};
|
|
([$($stack:tt)*] { $($tail:tt)* }) => {
|
|
$($stack)* {
|
|
remove_sections_inner!([] $($tail)*);
|
|
}
|
|
};
|
|
([$($stack:tt)*] $t:tt $($tail:tt)*) => {
|
|
remove_sections!([$($stack)* $t] $($tail)*);
|
|
};
|
|
}
|
|
|
|
macro_rules! deref {
|
|
($e:expr) => {
|
|
*$e
|
|
};
|
|
}
|
|
macro_rules! deref_twice {
|
|
($e:expr) => {
|
|
**$e
|
|
};
|
|
}
|
|
|
|
/// Implement a trait by delegation. By default as if we are delegating
|
|
/// from &G to G.
|
|
macro_rules! delegate_impl {
|
|
([] $($rest:tt)*) => {
|
|
delegate_impl! { [['a, G], G, &'a G, deref] $($rest)* }
|
|
};
|
|
([[$($param:tt)*], $self_type:ident, $self_wrap:ty, $self_map:ident]
|
|
pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* {
|
|
|
|
// "Escaped" associated types. Stripped before making the `trait`
|
|
// itself, but forwarded when delegating impls.
|
|
$(
|
|
@escape [type $assoc_name_ext:ident]
|
|
// Associated types. Forwarded.
|
|
)*
|
|
$(
|
|
@section type
|
|
$(
|
|
$(#[$_assoc_attr:meta])*
|
|
type $assoc_name:ident $(: $assoc_bound:ty)*;
|
|
)+
|
|
)*
|
|
// Methods. Forwarded. Using $self_map!(self) around the self argument.
|
|
// Methods must use receiver `self` or explicit type like `self: &Self`
|
|
// &self and &mut self are _not_ supported.
|
|
$(
|
|
@section self
|
|
$(
|
|
$(#[$_method_attr:meta])*
|
|
fn $method_name:ident(self $(: $self_selftype:ty)* $(,$marg:ident : $marg_ty:ty)*) $(-> $mret:ty)?;
|
|
)+
|
|
)*
|
|
// Arbitrary tail that is ignored when forwarding.
|
|
$(
|
|
@section nodelegate
|
|
$($tail:tt)*
|
|
)*
|
|
}) => {
|
|
impl<$($param)*> $name for $self_wrap where $self_type: $name {
|
|
$(
|
|
$(
|
|
type $assoc_name = $self_type::$assoc_name;
|
|
)*
|
|
)*
|
|
$(
|
|
type $assoc_name_ext = $self_type::$assoc_name_ext;
|
|
)*
|
|
$(
|
|
$(
|
|
fn $method_name(self $(: $self_selftype)* $(,$marg: $marg_ty)*) $(-> $mret)? {
|
|
$self_map!(self).$method_name($($marg),*)
|
|
}
|
|
)*
|
|
)*
|
|
}
|
|
}
|
|
}
|