Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  error.rs   Sprache: unbekannt

 
use proc_macro2::TokenStream;
use quote::quote;
use syn::{DeriveInput, Index};
use uniffi_meta::EnumShape;

use crate::{
    enum_::{rich_error_ffi_converter_impl, variant_metadata, EnumItem},
    ffiops,
    util::{
        chain, create_metadata_items, extract_docstring, ident_to_string, mod_path,
        try_metadata_value_from_usize, AttributeSliceExt,
    },
    DeriveOptions,
};

pub fn expand_error(input: DeriveInput, options: DeriveOptions) -> syn::Result<TokenStream> {
    let enum_item = EnumItem::new(input)?;
    let ffi_converter_impl = error_ffi_converter_impl(&enum_item, &options)?;
    let meta_static_var = options
        .generate_metadata
        .then(|| error_meta_static_var(&enum_item).unwrap_or_else(syn::Error::into_compile_error));

    let variant_errors: TokenStream = enum_item
        .enum_()
        .variants
        .iter()
        .flat_map(|variant| {
            chain(
                variant.attrs.uniffi_attr_args_not_allowed_here(),
                variant
                    .fields
                    .iter()
                    .flat_map(|field| field.attrs.uniffi_attr_args_not_allowed_here()),
            )
        })
        .map(syn::Error::into_compile_error)
        .collect();

    Ok(quote! {
        #ffi_converter_impl
        #meta_static_var
        #variant_errors
    })
}

fn error_ffi_converter_impl(item: &EnumItem, options: &DeriveOptions) -> syn::Result<TokenStream> {
    Ok(if item.is_flat_error() {
        flat_error_ffi_converter_impl(item, options)
    } else {
        rich_error_ffi_converter_impl(item, options)
    })
}

// FfiConverters for "flat errors"
//
// These are errors where we only lower the to_string() value, rather than any associated data.
// We lower the to_string() value unconditionally, whether the enum has associated data or not.
fn flat_error_ffi_converter_impl(item: &EnumItem, options: &DeriveOptions) -> TokenStream {
    let name = item.name();
    let ident = item.ident();
    let lower_impl_spec = options.ffi_impl_header("Lower", ident);
    let lift_impl_spec = options.ffi_impl_header("Lift", ident);
    let type_id_impl_spec = options.ffi_impl_header("TypeId", ident);
    let derive_ffi_traits = options.derive_ffi_traits(ident, &["LowerError", "ConvertError"]);
    let mod_path = match mod_path() {
        Ok(p) => p,
        Err(e) => return e.into_compile_error(),
    };

    let lower_impl = {
        let mut match_arms: Vec<_> = item
            .enum_()
            .variants
            .iter()
            .enumerate()
            .map(|(i, v)| {
                let v_ident = &v.ident;
                let idx = Index::from(i + 1);
                let write_string = ffiops::write(quote! { ::std::string::String });

                quote! {
                    Self::#v_ident { .. } => {
                        ::uniffi::deps::bytes::BufMut::put_i32(buf, #idx);
                        #write_string(error_msg, buf);
                    }
                }
            })
            .collect();
        if item.is_non_exhaustive() {
            match_arms.push(quote! {
                _ => ::std::panic!("Unexpected variant in non-exhaustive enum"),
            })
        }

        let lower = ffiops::lower_into_rust_buffer(quote! { Self });

        quote! {
            #[automatically_derived]
            unsafe #lower_impl_spec {
                type FfiType = ::uniffi::RustBuffer;

                fn write(obj: Self, buf: &mut ::std::vec::Vec<u8>) {
                    let error_msg = ::std::string::ToString::to_string(&obj);
                    match obj { #(#match_arms)* }
                }

                fn lower(obj: Self) -> ::uniffi::RustBuffer {
                    #lower(obj)
                }
            }
        }
    };

    let lift_impl = if item.generate_error_try_read() {
        let match_arms = item.enum_().variants.iter().enumerate().map(|(i, v)| {
            let v_ident = &v.ident;
            let idx = Index::from(i + 1);

            quote! {
                #idx => Self::#v_ident,
            }
        });
        let try_lift = ffiops::try_lift_from_rust_buffer(quote! { Self });
        quote! {
            #[automatically_derived]
            unsafe #lift_impl_spec {
                type FfiType = ::uniffi::RustBuffer;

                fn try_read(buf: &mut &[::std::primitive::u8]) -> ::uniffi::deps::anyhow::Result<Self> {
                    ::std::result::Result::Ok(match ::uniffi::deps::bytes::Buf::get_i32(buf) {
                        #(#match_arms)*
                        v => ::uniffi::deps::anyhow::bail!("Invalid #ident enum value: {}", v),
                    })
                }

                fn try_lift(v: ::uniffi::RustBuffer) -> ::uniffi::deps::anyhow::Result<Self> {
                    #try_lift(v)
                }
            }
        }
    } else {
        quote! {
            // Lifting flat errors is not currently supported, but we still define the trait so
            // that dicts containing flat errors don't cause compile errors (see ReturnOnlyDict in
            // coverall.rs).
            //
            // Note: it would be better to not derive `Lift` for dictionaries containing flat
            // errors, but getting the trait bounds and derived impls there would be much harder.
            // For now, we just fail at runtime.
            #[automatically_derived]
            unsafe #lift_impl_spec {
                type FfiType = ::uniffi::RustBuffer;

                fn try_read(buf: &mut &[::std::primitive::u8]) -> ::uniffi::deps::anyhow::Result<Self> {
                    ::std::panic!("Can't lift flat errors")
                }

                fn try_lift(v: ::uniffi::RustBuffer) -> ::uniffi::deps::anyhow::Result<Self> {
                    ::std::panic!("Can't lift flat errors")
                }
            }
        }
    };

    quote! {
        #lower_impl
        #lift_impl

        #[automatically_derived]
        #type_id_impl_spec {
            const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TYPE_ENUM)
                .concat_str(#mod_path)
                .concat_str(#name);
        }

        #derive_ffi_traits
    }
}

pub(crate) fn error_meta_static_var(item: &EnumItem) -> syn::Result<TokenStream> {
    let name = item.name();
    let module_path = mod_path()?;
    let non_exhaustive = item.is_non_exhaustive();
    let docstring = item.docstring();
    let flat = item.is_flat_error();
    let shape = EnumShape::Error { flat }.as_u8();
    let mut metadata_expr = quote! {
            ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::ENUM)
                .concat_str(#module_path)
                .concat_str(#name)
                .concat_value(#shape)
                .concat_bool(false) // discr_type: None
    };
    if flat {
        metadata_expr.extend(flat_error_variant_metadata(item)?)
    } else {
        metadata_expr.extend(variant_metadata(item)?);
    }
    metadata_expr.extend(quote! {
        .concat_bool(#non_exhaustive)
        .concat_long_str(#docstring)
    });
    Ok(create_metadata_items("error", &name, metadata_expr, None))
}

pub fn flat_error_variant_metadata(item: &EnumItem) -> syn::Result<Vec<TokenStream>> {
    let enum_ = item.enum_();
    let variants_len =
        try_metadata_value_from_usize(enum_.variants.len(), "UniFFI limits enums to 256 variants")?;
    std::iter::once(Ok(quote! { .concat_value(#variants_len) }))
        .chain(enum_.variants.iter().map(|v| {
            let name = ident_to_string(&v.ident);
            let docstring = extract_docstring(&v.attrs)?;
            Ok(quote! {
                .concat_str(#name)
                .concat_long_str(#docstring)
            })
        }))
        .collect()
}

[ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge