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

    {%- if f.is_message %}
    type {{ f.ident_camel_unesc }}MessageType<'this>: {{ f.trait_field_message_trait_path }}
        where Self: 'this;
    {%- endif %} {#- if f.is_message #}

    {%- if f.is_repeated %}

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

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

    {%- if f.is_message %}
    {#- the getter method returns Option<T> for message field #}
    fn {{ f.ident }}<'this>(&'this self) -> ::std::option::Option<{{ f.trait_scalar_getter_type }}> {
        self.{{ f.ident_unesc }}_opt()
    }
    {%- else %}
    fn {{ f.ident }}<'this>(&'this self) -> {{ f.trait_scalar_getter_type }} {
        {%- if f.has_default_value %}
        self.{{ f.ident_unesc }}_opt().unwrap_or({{ f.default_value }})
        {%- else %}
        self.{{ f.ident_unesc }}_opt().unwrap_or_else(::std::default::Default::default)
        {%- endif %}
    }
    {%- endif %}
    fn has_{{ f.ident_unesc }}<'this>(&'this self) -> bool {
        self.{{ f.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 !f.is_explicit_oneof_field %}
    fn {{ f.ident_unesc }}_opt<'this>(&'this self) -> ::std::option::Option<{{ f.trait_scalar_getter_type }}> {
        ::std::option::Option::None
    }
    {%- endif %}

    {%- endif %} {#- if f.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, Self>
            {%- else %}
            <'this>
            {%- endif %}
            {%- endif %}
        >
    {
        ::std::option::Option::None
    }

    {%- for f in oneof.fields %}
    fn {{ f.getter_ident_unesc }}_opt<'this>(&'this self) -> Option<{{ f.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::{{ f.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 f in m.fields %}
        {%- if f.is_message %}
        type {{ f.ident_camel_unesc }}MessageType<'this> where Self: 'this = <$ty>::{{ f.ident_camel_unesc }}MessageType<'this>;
        {%- endif %}

        {%- if f.is_repeated %}

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

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

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

        {%- endif %} {#- if f.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, Self>
                {%- else %}
                <'this>
                {%- 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);
}

impl<'bump, T> {{ m.trait_ident }} for ::puroro::bumpalo::boxed::Box<'bump, T>
where
    T: {{ m.trait_ident }}
{
    {{ m.trait_delegate_macro_ident }}!(T);
}

impl<T> {{ m.trait_ident }} for ::puroro::BumpaloOwned<T>
where
    T: {{ m.trait_ident }}
{
    {{ m.trait_delegate_macro_ident }}!(T);
}

{%- include "trait_impls/empty.rs.txt" %}
{%- include "trait_impls/merged.rs.txt" %}
{%- include "trait_impls/either.rs.txt" %}
{%- include "trait_impls/option.rs.txt" %}
