fn enum_or_error_ffi_converter_impl()

in uniffi_macros/src/enum_.rs [161:267]


fn enum_or_error_ffi_converter_impl(
    item: &EnumItem,
    options: &DeriveOptions,
    metadata_type_code: TokenStream,
) -> TokenStream {
    let name = item.name();
    let ident = item.ident();
    let impl_spec = options.ffi_impl_header("FfiConverter", ident);
    let derive_ffi_traits = options.derive_all_ffi_traits(ident);
    let mod_path = match mod_path() {
        Ok(p) => p,
        Err(e) => return e.into_compile_error(),
    };
    let mut write_match_arms: Vec<_> = item
        .enum_()
        .variants
        .iter()
        .enumerate()
        .map(|(i, v)| {
            let v_ident = &v.ident;
            let field_idents = v
                .fields
                .iter()
                .enumerate()
                .map(|(i, f)| {
                    f.ident
                        .clone()
                        .unwrap_or_else(|| Ident::new(&format!("e{i}"), f.span()))
                })
                .collect::<Vec<Ident>>();
            let idx = Index::from(i + 1);
            let write_fields =
                std::iter::zip(v.fields.iter(), field_idents.iter()).map(|(f, ident)| {
                    let write = ffiops::write(&f.ty);
                    quote! { #write(#ident, buf); }
                });
            let is_tuple = v.fields.iter().any(|f| f.ident.is_none());
            let fields = if is_tuple {
                quote! { ( #(#field_idents),* ) }
            } else {
                quote! { { #(#field_idents),* } }
            };

            quote! {
                Self::#v_ident #fields => {
                    ::uniffi::deps::bytes::BufMut::put_i32(buf, #idx);
                    #(#write_fields)*
                }
            }
        })
        .collect();
    if item.is_non_exhaustive() {
        write_match_arms.push(quote! {
            _ => ::std::panic!("Unexpected variant in non-exhaustive enum"),
        })
    }
    let write_impl = quote! {
        match obj { #(#write_match_arms)* }
    };

    let try_read_match_arms = item.enum_().variants.iter().enumerate().map(|(i, v)| {
        let idx = Index::from(i + 1);
        let v_ident = &v.ident;
        let is_tuple = v.fields.iter().any(|f| f.ident.is_none());
        let try_read_fields = v.fields.iter().map(try_read_field);

        if is_tuple {
            quote! {
                #idx => Self::#v_ident ( #(#try_read_fields)* ),
            }
        } else {
            quote! {
                #idx => Self::#v_ident { #(#try_read_fields)* },
            }
        }
    });
    let error_format_string = format!("Invalid {name} enum value: {{}}");
    let try_read_impl = quote! {
        ::uniffi::check_remaining(buf, 4)?;

        ::std::result::Result::Ok(match ::uniffi::deps::bytes::Buf::get_i32(buf) {
            #(#try_read_match_arms)*
            v => ::uniffi::deps::anyhow::bail!(#error_format_string, v),
        })
    };

    quote! {
        #[automatically_derived]
        unsafe #impl_spec {
            ::uniffi::ffi_converter_rust_buffer_lift_and_lower!(crate::UniFfiTag);

            fn write(obj: Self, buf: &mut ::std::vec::Vec<u8>) {
                #write_impl
            }

            fn try_read(buf: &mut &[::std::primitive::u8]) -> ::uniffi::deps::anyhow::Result<Self> {
                #try_read_impl
            }

            const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(#metadata_type_code)
                .concat_str(#mod_path)
                .concat_str(#name);
        }

        #derive_ffi_traits
    }
}