
/// Define a trait as usual, and a macro that can be used to instantiate
/// implementations of it.
///
/// Well almost: There *must* be markers of
/// `@section type`, `@section self` and `@section self_ref`, `@section self_mut`,
/// `@section ignore`, before the associated types, `self` methods
/// and `&self` methods, `&mut self` methods and methods to skip in delegation
/// respectively.
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)*
        }
    }
}

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)* {
        $(
        @escape [type $assoc_name_ext:ident]
        )*
        $(
        @section type
        $(
            $(#[$_attr1:meta])*
            type $assoc_name:ident $(: $bound:ty)*;
        )+
        )*
        $(
        @section self
        $(
            $(#[$_attr2:meta])*
            fn $fname_self:ident(self $(,$arg2:ident : $argty2:ty)*) -> $ret2:ty;
        )+
        )*
        $(
        @section self_ref
        $(
            $(#[$_attr3:meta])*
            fn $fname:ident(&self $(,$arg:ident : $argty:ty)*) -> $ret:ty;
        )+
        )*
        $(
        @section self_mut
        $(
            $(#[$_attr4:meta])*
            fn $fname_mut:ident(&mut self $(,$arg4:ident : $argty4:ty)*) -> $ret4:ty;
        )+
        )*
        $(
        @section ignore
        $($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 $fname_self(self $(,$arg2: $argty2)*) -> $ret2 {
                    $self_map!(self).$fname_self($($arg2),*)
                }
            )*
            )*
            $(
            $(
                fn $fname(&self $(,$arg: $argty)*) -> $ret {
                    $self_map!(self).$fname($($arg),*)
                }
            )*
            )*
            $(
            $(
                fn $fname_mut(&mut self $(,$arg4: $argty4)*) -> $ret4 {
                    $self_map!(self).$fname_mut($($arg4),*)
                }
            )*
            )*
        }
    }
}

