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(),
}; letmut 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);
pub(crate) fn enum_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 shape = EnumShape::Enum.as_u8();
fn variant_value(v: &Variant) -> syn::Result<TokenStream> { let Some((_, e)) = &v.discriminant else { return Ok(quote! { .concat_bool(false) });
}; // Attempting to expose an enum value which we don't understand is a hard-error // rather than silently ignoring it. If we had the ability to emit a warning that // might make more sense.
// We can't sanely handle most expressions other than literals, but we can handle // negative literals. letmut negate = false; let lit = match e {
Expr::Lit(lit) => lit,
Expr::Unary(expr_unary) if matches!(expr_unary.op, syn::UnOp::Neg(_)) => {
negate = true; match *expr_unary.expr {
Expr::Lit(ref lit) => lit,
_ => { return Err(syn::Error::new_spanned(
e, "UniFFI disciminant values must be a literal",
));
}
}
}
_ => { return Err(syn::Error::new_spanned(
e, "UniFFI disciminant values must be a literal",
));
}
}; let Lit::Int(ref intlit) = lit.lit else { return Err(syn::Error::new_spanned(
v, "UniFFI disciminant values must be a literal integer",
));
}; if !intlit.suffix().is_empty() { return Err(syn::Error::new_spanned(
intlit, "integer literals with suffix not supported by UniFFI here",
));
} let digits = if negate {
format!("-{}", intlit.base10_digits())
} else {
intlit.base10_digits().to_string()
};
Ok(quote! {
.concat_bool(true)
.concat_value(::uniffi::metadata::codes::LIT_INT)
.concat_str(#digits)
})
}
pubfn 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 fields_len = try_metadata_value_from_usize(
v.fields.len(), "UniFFI limits enum variants to 256 fields",
)?;
let field_names = v
.fields
.iter()
.map(|f| f.ident.as_ref().map(ident_to_string).unwrap_or_default())
.collect::<Vec<_>>();
let name = ident_to_string(&v.ident); let value_tokens = variant_value(v)?; let docstring = extract_docstring(&v.attrs)?; let field_docstrings = v
.fields
.iter()
.map(|f| extract_docstring(&f.attrs))
.collect::<syn::Result<Vec<_>>>()?; let field_type_id_metas = v.fields.iter().map(|f| ffiops::type_id_meta(&f.ty));
Ok(quote! {
.concat_str(#name) #value_tokens
.concat_value(#fields_len) #(
.concat_str(#field_names)
.concat(#field_type_id_metas) // field defaults not yet supported for enums
.concat_bool(false)
.concat_long_str(#field_docstrings)
)*
.concat_long_str(#docstring)
})
}))
.collect()
}
/// Handle #[uniffi(...)] attributes for enums #[derive(Clone, Default)] pubstruct EnumAttr { // All of these attributes are only relevant for errors, but they're defined here so that we // can reuse EnumItem for errors. pub flat_error: Option<kw::flat_error>, pub with_try_read: Option<kw::with_try_read>,
}
impl UniffiAttributeArgs for EnumAttr { fn parse_one(input: ParseStream<'_>) -> syn::Result<Self> { let lookahead = input.lookahead1(); if lookahead.peek(kw::flat_error) {
Ok(Self {
flat_error: input.parse()?,
..Self::default()
})
} elseif lookahead.peek(kw::with_try_read) {
Ok(Self {
with_try_read: input.parse()?,
..Self::default()
})
} elseif lookahead.peek(kw::handle_unknown_callback_error) { // Not used anymore, but still allowed
Ok(Self::default())
} else {
Err(lookahead.error())
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.