Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/uniffi_macros/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 5 kB image not shown  

Quelle  record.rs   Sprache: unbekannt

 
Spracherkennung für: .rs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use syn::{parse::ParseStream, Data, DataStruct, DeriveInput, Field, Token};

use crate::{
    default::{default_value_metadata_calls, DefaultValue},
    ffiops,
    util::{
        create_metadata_items, either_attribute_arg, extract_docstring, ident_to_string, kw,
        mod_path, try_metadata_value_from_usize, try_read_field, AttributeSliceExt,
        UniffiAttributeArgs,
    },
    DeriveOptions,
};

/// Stores parsed data from the Derive Input for the struct.
struct RecordItem {
    ident: Ident,
    record: DataStruct,
    docstring: String,
}

impl RecordItem {
    fn new(input: DeriveInput) -> syn::Result<Self> {
        let record = match input.data {
            Data::Struct(s) => s,
            _ => {
                return Err(syn::Error::new(
                    Span::call_site(),
                    "This derive must only be used on structs",
                ));
            }
        };
        Ok(Self {
            ident: input.ident,
            record,
            docstring: extract_docstring(&input.attrs)?,
        })
    }

    fn ident(&self) -> &Ident {
        &self.ident
    }

    fn name(&self) -> String {
        ident_to_string(&self.ident)
    }

    fn struct_(&self) -> &DataStruct {
        &self.record
    }

    fn docstring(&self) -> &str {
        self.docstring.as_str()
    }
}

pub fn expand_record(input: DeriveInput, options: DeriveOptions) -> syn::Result<TokenStream> {
    if let Some(e) = input.attrs.uniffi_attr_args_not_allowed_here() {
        return Err(e);
    }
    let record = RecordItem::new(input)?;
    let ffi_converter =
        record_ffi_converter_impl(&record, &options).unwrap_or_else(syn::Error::into_compile_error);
    let meta_static_var = options
        .generate_metadata
        .then(|| record_meta_static_var(&record).unwrap_or_else(syn::Error::into_compile_error));

    Ok(quote! {
        #ffi_converter
        #meta_static_var
    })
}

fn record_ffi_converter_impl(
    record: &RecordItem,
    options: &DeriveOptions,
) -> syn::Result<TokenStream> {
    let ident = record.ident();
    let impl_spec = options.ffi_impl_header("FfiConverter", ident);
    let derive_ffi_traits = options.derive_all_ffi_traits(ident);
    let name = ident_to_string(ident);
    let mod_path = mod_path()?;
    let write_impl: TokenStream = record.struct_().fields.iter().map(write_field).collect();
    let try_read_fields: TokenStream = record.struct_().fields.iter().map(try_read_field).collect();

    Ok(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> {
                ::std::result::Result::Ok(Self { #try_read_fields })
            }

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

        #derive_ffi_traits
    })
}

fn write_field(f: &Field) -> TokenStream {
    let ident = &f.ident;
    let write = ffiops::write(&f.ty);
    quote! {
        #write(obj.#ident, buf);
    }
}

#[derive(Default)]
pub struct FieldAttributeArguments {
    pub(crate) default: Option<DefaultValue>,
}

impl UniffiAttributeArgs for FieldAttributeArguments {
    fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> {
        let _: kw::default = input.parse()?;
        let _: Token![=] = input.parse()?;
        let default = input.parse()?;
        Ok(Self {
            default: Some(default),
        })
    }

    fn merge(self, other: Self) -> syn::Result<Self> {
        Ok(Self {
            default: either_attribute_arg(self.default, other.default)?,
        })
    }
}

fn record_meta_static_var(record: &RecordItem) -> syn::Result<TokenStream> {
    let name = record.name();
    let docstring = record.docstring();
    let module_path = mod_path()?;
    let fields_len = try_metadata_value_from_usize(
        record.struct_().fields.len(),
        "UniFFI limits structs to 256 fields",
    )?;

    let concat_fields: TokenStream = record
        .struct_()
        .fields
        .iter()
        .map(|f| {
            let attrs = f
                .attrs
                .parse_uniffi_attr_args::<FieldAttributeArguments>()?;

            let name = ident_to_string(f.ident.as_ref().unwrap());
            let docstring = extract_docstring(&f.attrs)?;
            let default = default_value_metadata_calls(&attrs.default)?;
            let type_id_meta = ffiops::type_id_meta(&f.ty);

            // Note: fields need to implement both `Lower` and `Lift` to be used in a record.  The
            // TYPE_ID_META should be the same for both traits.
            Ok(quote! {
                .concat_str(#name)
                .concat(#type_id_meta)
                #default
                .concat_long_str(#docstring)
            })
        })
        .collect::<syn::Result<_>>()?;

    Ok(create_metadata_items(
        "record",
        &name,
        quote! {
            ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::RECORD)
                .concat_str(#module_path)
                .concat_str(#name)
                .concat_value(#fields_len)
                #concat_fields
                .concat_long_str(#docstring)
        },
        None,
    ))
}

[ Dauer der Verarbeitung: 0.36 Sekunden  ]