{%- for m in messages %}
pub trait {{ m.trait_ident }} {
    {%- for field in m.fields %}

    {%- match field.trait_maybe_field_message_trait_path %}
    {%- when Some with (field_msg_path) %}
    type Field{{ field.number }}MessageType<'this>:
        {{ field_msg_path }} + ::std::clone::Clone + ::std::cmp::PartialEq + ::std::fmt::Debug
        where Self: 'this;
    {%- else %}
    {%- endmatch %}

    {%- if field.is_repeated %}

    type Field{{ field.number }}RepeatedType<'this>:
        ::puroro::RepeatedField<'this>
        + ::std::iter::IntoIterator<Item = {{ field.trait_scalar_getter_type }}>
    where Self: 'this;
    fn {{ field.ident }}<'this>(&'this self) -> Self::Field{{ field.number }}RepeatedType<'this>;

    {%- else %} {#- if field.is_repeated #}

    {%- if field.is_message %}
    {#- the getter method returns Option<T> for message field #}
    fn {{ field.ident }}<'this>(&'this self) -> ::std::option::Option<{{ field.trait_scalar_getter_type }}> {
        self.{{ field.ident_unesc }}_opt()
    }
    {%- else %}
    fn {{ field.ident }}<'this>(&'this self) -> {{ field.trait_scalar_getter_type }} {
        self.{{ field.ident_unesc }}_opt().unwrap_or_else(::std::default::Default::default)
    }
    {%- endif %}
    fn has_{{ field.ident_unesc }}<'this>(&'this self) -> bool {
        self.{{ field.ident_unesc }}_opt().is_some()
    }
    {#-
     # Oneof items will have same interfaces with the scalar fields, but its default implementation 
     # can depend on the oneof field getter's return value so skip it for now and define those at below.
     #}
    {%- if !field.is_explicit_oneof_field %}
    fn {{ field.ident_unesc }}_opt<'this>(&'this self) -> ::std::option::Option<{{ field.trait_scalar_getter_type }}> {
        ::std::option::Option::None
    }
    {%- endif %}

    {%- endif %} {#- if field.is_repeated #}
    {%- endfor %}

    {%- for oneof in m.oneofs %}
    fn {{ oneof.field_ident }}<'this>(&'this self) ->
        ::std::option::Option<
            super::_puroro_nested::{{ m.submodule_ident }}::_puroro_oneofs::{{ oneof.enum_ident }}
            {%- if oneof.has_ld_field %}
            {%- if oneof.has_message_field %}
            <'this, ::puroro::internal::bool::False, Self>
            {%- else %}
            <'this, ::puroro::internal::bool::False>
            {%- endif %}
            {%- endif %}
        >
    {
        ::std::option::Option::None
    }

    {%- for field in oneof.fields %}
    pub fn {{ field.getter_ident_unesc }}_opt<'this>(&'this self) -> Option<{{ field.trait_getter_type }}> {
        use super::_puroro_nested::{{ m.submodule_ident }}::_puroro_oneofs::{{ oneof.enum_ident }} as E;
        self.{{ oneof.field_ident }}().and_then(|oneof| {
            #[allow(irrefutable_let_patterns)]
            if let E::{{ field.ident }}(v) = oneof {
                ::std::option::Option::Some(v)
            } else {
                ::std::option::Option::None
            }
        })
    }
    {%- endfor %}
    {%- endfor %}
}

macro_rules! {{ m.trait_delegate_macro_ident }} {
    ($ty:ty) => {
        {%- for field in m.fields %}
        {%- if field.is_message %}
        type Field{{ field.number }}MessageType<'this> where Self: 'this = <$ty>::Field{{ field.number }}MessageType<'this>;
        {%- endif %}

        {%- if field.is_repeated %}

        type Field{{ field.number }}RepeatedType<'this> where Self: 'this = <$ty>::Field{{ field.number }}RepeatedType<'this>;
        fn {{ field.ident }}<'this>(&'this self) -> Self::Field{{ field.number }}RepeatedType<'this> {
            (**self).{{ field.ident }}()
        }

        {%- else %} {#- if field.is_repeated #}

        {%- if !field.is_explicit_oneof_field %}
        fn {{ field.ident_unesc }}_opt<'this>(&'this self) -> ::std::option::Option<{{ field.trait_scalar_getter_type }}> {
            (**self).{{ field.ident_unesc }}_opt()
        }
        {%- endif %}

        {%- endif %} {#- if field.is_repeated #}

        {%- endfor %}

        {%- for oneof in m.oneofs %}
        fn {{ oneof.field_ident }}<'this>(&'this self) ->
            ::std::option::Option<
                super::_puroro_nested::{{ m.submodule_ident }}::_puroro_oneofs::{{ oneof.enum_ident }}
                {%- if oneof.has_ld_field %}
                {%- if oneof.has_message_field %}
                <'this, ::puroro::internal::bool::False, Self>
                {%- else %}
                <'this, ::puroro::internal::bool::False>
                {%- endif %}
                {%- endif %}
            >
        {
            (**self).{{ oneof.field_ident }}().map(|v| v.into())
        }
        {%- endfor %}
    };
}

impl<T> {{ m.trait_ident }} for &'_ T
where
    T: {{ m.trait_ident }}
{
    {{ m.trait_delegate_macro_ident }}!(T);
}

impl<T> {{ m.trait_ident }} for &'_ mut T
where
    T: {{ m.trait_ident }}
{
    {{ m.trait_delegate_macro_ident }}!(T);
}

impl<T> {{ m.trait_ident }} for ::std::boxed::Box<T>
where
    T: {{ m.trait_ident }}
{
    {{ m.trait_delegate_macro_ident }}!(T);
}

{%- endfor %}
