
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()
    }

    fn {{ f.ident_unesc }}_opt<'this>(&'this self) -> ::std::option::Option<{{ f.trait_scalar_getter_type }}> {
        ::std::option::Option::None
    }

    {%- 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 }}{{ oneof.enum_maybe_gp_self }}
        >
    {
        use super::_puroro_nested::{{ m.submodule_ident }}::_puroro_oneofs::{{ oneof.enum_ident }} as E;

        {%- for f in oneof.fields %}
        if let ::std::option::Option::Some(val) = self.{{ f.getter_ident_unesc }}_opt() {
            return ::std::option::Option::Some(E::{{ f.ident }}(val))
        }
        {%- endfor %} {#- for f in oneof.fields #}

        ::std::option::Option::None
    }
    {%- 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 #}

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

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

        {%- 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" %}
