impl<T, U> {{ m.trait_ident }} for ::puroro::Either<T, U>
where
    T: {{ m.trait_ident }},
    U: {{ m.trait_ident }},
{
    {%- for f in m.fields %}

    {%- if f.is_message %}
    type {{ f.ident_camel_unesc }}MessageType<'this> where Self: 'this = ::puroro::Either<
        <T as {{ m.trait_ident }}>::{{ f.ident_camel_unesc }}MessageType<'this>,
        <U as {{ m.trait_ident }}>::{{ f.ident_camel_unesc }}MessageType<'this>,
    >;
    {%- endif %}

    {%- if f.is_repeated %}

    {%- let either_repeated_field_type %}
    {%- if f.is_message %}
    {%- let either_repeated_field_type = "EitherRepeatedMessageField" %}
    {%- else %}
    {%- let either_repeated_field_type = "EitherRepeatedField" %}
    {%- endif %}
    type {{ f.ident_camel_unesc }}RepeatedType<'this> where Self: 'this
        = ::puroro::internal::impls::either::{{ either_repeated_field_type }}<
            <T as {{ m.trait_ident }}>::{{ f.ident_camel_unesc }}RepeatedType<'this>,
            <U as {{ m.trait_ident }}>::{{ f.ident_camel_unesc }}RepeatedType<'this>,
        >;

    fn {{ f.ident }}<'this>(&'this self) -> Self::{{ f.ident_camel_unesc }}RepeatedType<'this>
    {
        ::puroro::internal::impls::either::{{ either_repeated_field_type }}::new(self
            .as_ref()
            .map_left(
                |t| <T as {{ m.trait_ident }}>::{{ f.ident }}(t)
            )
            .map_right(
                |u| <U as {{ m.trait_ident }}>::{{ f.ident }}(u)
            )
        )
    }

    {%- 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 }}>
    {
        {%- if f.is_message %}
        self.as_ref().either(
            |t| <T as {{ m.trait_ident }}>::{{ f.ident_unesc }}_opt(t).map(
                |t| ::puroro::Either::Left(t)
            ),
            |u| <U as {{ m.trait_ident }}>::{{ f.ident_unesc }}_opt(u).map(
                |u| ::puroro::Either::Right(u)
            ),
        )
        {%- else %}
        self.as_ref().either(
            |t| <T as {{ m.trait_ident }}>::{{ f.ident_unesc }}_opt(t),
            |u| <U as {{ m.trait_ident }}>::{{ f.ident_unesc }}_opt(u),
        )
        {%- endif %}
    }
    {%- endif %}

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

    {%- endfor %} {#- for f in m.fields #}

    {%- for oneof in m.oneofs %}
    fn {{ oneof.field_ident }}(&self) ->
        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;
        match self.as_ref().either(
            |t| t.{{ oneof.field_ident }}().map(|t| ::puroro::Either::Left(t)),
            |u| u.{{ oneof.field_ident }}().map(|u| ::puroro::Either::Right(u)),
        ) {
            {%- for f in oneof.fields %}
            Some(::puroro::Either::Left(E::{{ f.ident }}(v))) => {
                {%- if f.is_message %}
                Some(E::{{ f.ident }}(::puroro::Either::Left(v)))
                {%- else %}
                Some(E::{{ f.ident }}(v))
                {%- endif %}
            }
            Some(::puroro::Either::Right(E::{{ f.ident }}(v))) => {
                {%- if f.is_message %}
                Some(E::{{ f.ident }}(::puroro::Either::Right(v)))
                {%- else %}
                Some(E::{{ f.ident }}(v))
                {%- endif %}
            }
            {%- endfor %}
            None => None,
        }
    }
    {%- endfor %}
}
