summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_macros/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/uniffi_macros/src/error.rs')
-rw-r--r--third_party/rust/uniffi_macros/src/error.rs101
1 files changed, 73 insertions, 28 deletions
diff --git a/third_party/rust/uniffi_macros/src/error.rs b/third_party/rust/uniffi_macros/src/error.rs
index a2ee7cf603..804b438003 100644
--- a/third_party/rust/uniffi_macros/src/error.rs
+++ b/third_party/rust/uniffi_macros/src/error.rs
@@ -6,11 +6,11 @@ use syn::{
};
use crate::{
- enum_::{rich_error_ffi_converter_impl, variant_metadata},
+ enum_::{rich_error_ffi_converter_impl, variant_metadata, EnumAttr},
util::{
- chain, create_metadata_items, derive_ffi_traits, either_attribute_arg, ident_to_string, kw,
- mod_path, parse_comma_separated, tagged_impl_header, try_metadata_value_from_usize,
- AttributeSliceExt, UniffiAttributeArgs,
+ chain, create_metadata_items, derive_ffi_traits, either_attribute_arg, extract_docstring,
+ ident_to_string, kw, mod_path, parse_comma_separated, tagged_impl_header,
+ try_metadata_value_from_usize, AttributeSliceExt, UniffiAttributeArgs,
},
};
@@ -30,13 +30,14 @@ pub fn expand_error(
}
};
let ident = &input.ident;
+ let docstring = extract_docstring(&input.attrs)?;
let mut attr: ErrorAttr = input.attrs.parse_uniffi_attr_args()?;
if let Some(attr_from_udl_mode) = attr_from_udl_mode {
attr = attr.merge(attr_from_udl_mode)?;
}
- let ffi_converter_impl = error_ffi_converter_impl(ident, &enum_, &attr, udl_mode);
+ let ffi_converter_impl = error_ffi_converter_impl(ident, &enum_, &attr, udl_mode)?;
let meta_static_var = (!udl_mode).then(|| {
- error_meta_static_var(ident, &enum_, attr.flat.is_some())
+ error_meta_static_var(ident, docstring, &enum_, &attr)
.unwrap_or_else(syn::Error::into_compile_error)
});
@@ -67,23 +68,23 @@ fn error_ffi_converter_impl(
enum_: &DataEnum,
attr: &ErrorAttr,
udl_mode: bool,
-) -> TokenStream {
- if attr.flat.is_some() {
- flat_error_ffi_converter_impl(ident, enum_, udl_mode, attr.with_try_read.is_some())
+) -> syn::Result<TokenStream> {
+ Ok(if attr.flat.is_some() {
+ flat_error_ffi_converter_impl(ident, enum_, udl_mode, attr)
} else {
- rich_error_ffi_converter_impl(ident, enum_, udl_mode)
- }
+ rich_error_ffi_converter_impl(ident, enum_, udl_mode, &attr.clone().try_into()?)
+ })
}
// FfiConverters for "flat errors"
//
-// These are errors where we only lower the to_string() value, rather than any assocated data.
+// 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(
ident: &Ident,
enum_: &DataEnum,
udl_mode: bool,
- implement_lift: bool,
+ attr: &ErrorAttr,
) -> TokenStream {
let name = ident_to_string(ident);
let lower_impl_spec = tagged_impl_header("Lower", ident, udl_mode);
@@ -95,7 +96,7 @@ fn flat_error_ffi_converter_impl(
};
let lower_impl = {
- let match_arms = enum_.variants.iter().enumerate().map(|(i, v)| {
+ let mut match_arms: Vec<_> = enum_.variants.iter().enumerate().map(|(i, v)| {
let v_ident = &v.ident;
let idx = Index::from(i + 1);
@@ -105,7 +106,12 @@ fn flat_error_ffi_converter_impl(
<::std::string::String as ::uniffi::Lower<crate::UniFfiTag>>::write(error_msg, buf);
}
}
- });
+ }).collect();
+ if attr.non_exhaustive.is_some() {
+ match_arms.push(quote! {
+ _ => panic!("Unexpected variant in non-exhaustive enum"),
+ })
+ }
quote! {
#[automatically_derived]
@@ -128,7 +134,7 @@ fn flat_error_ffi_converter_impl(
}
};
- let lift_impl = if implement_lift {
+ let lift_impl = if attr.with_try_read.is_some() {
let match_arms = enum_.variants.iter().enumerate().map(|(i, v)| {
let v_ident = &v.ident;
let idx = Index::from(i + 1);
@@ -192,42 +198,53 @@ fn flat_error_ffi_converter_impl(
pub(crate) fn error_meta_static_var(
ident: &Ident,
+ docstring: String,
enum_: &DataEnum,
- flat: bool,
+ attr: &ErrorAttr,
) -> syn::Result<TokenStream> {
let name = ident_to_string(ident);
let module_path = mod_path()?;
+ let flat = attr.flat.is_some();
+ let non_exhaustive = attr.non_exhaustive.is_some();
let mut metadata_expr = quote! {
- ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::ERROR)
- // first our is-flat flag
- .concat_bool(#flat)
- // followed by an enum
+ ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::ENUM)
.concat_str(#module_path)
.concat_str(#name)
+ .concat_option_bool(Some(#flat))
+ .concat_bool(false) // discr_type: None
};
if flat {
metadata_expr.extend(flat_error_variant_metadata(enum_)?)
} else {
metadata_expr.extend(variant_metadata(enum_)?);
}
+ 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(enum_: &DataEnum) -> syn::Result<Vec<TokenStream>> {
let variants_len =
try_metadata_value_from_usize(enum_.variants.len(), "UniFFI limits enums to 256 variants")?;
- Ok(std::iter::once(quote! { .concat_value(#variants_len) })
+ std::iter::once(Ok(quote! { .concat_value(#variants_len) }))
.chain(enum_.variants.iter().map(|v| {
let name = ident_to_string(&v.ident);
- quote! { .concat_str(#name) }
+ let docstring = extract_docstring(&v.attrs)?;
+ Ok(quote! {
+ .concat_str(#name)
+ .concat_long_str(#docstring)
+ })
}))
- .collect())
+ .collect()
}
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct ErrorAttr {
- flat: Option<kw::flat_error>,
- with_try_read: Option<kw::with_try_read>,
+ pub flat: Option<kw::flat_error>,
+ pub with_try_read: Option<kw::with_try_read>,
+ pub non_exhaustive: Option<kw::non_exhaustive>,
}
impl UniffiAttributeArgs for ErrorAttr {
@@ -243,8 +260,13 @@ impl UniffiAttributeArgs for ErrorAttr {
with_try_read: input.parse()?,
..Self::default()
})
+ } else if lookahead.peek(kw::non_exhaustive) {
+ Ok(Self {
+ non_exhaustive: input.parse()?,
+ ..Self::default()
+ })
} else if lookahead.peek(kw::handle_unknown_callback_error) {
- // Not used anymore, but still lallowed
+ // Not used anymore, but still allowed
Ok(Self::default())
} else {
Err(lookahead.error())
@@ -255,6 +277,7 @@ impl UniffiAttributeArgs for ErrorAttr {
Ok(Self {
flat: either_attribute_arg(self.flat, other.flat)?,
with_try_read: either_attribute_arg(self.with_try_read, other.with_try_read)?,
+ non_exhaustive: either_attribute_arg(self.non_exhaustive, other.non_exhaustive)?,
})
}
}
@@ -265,3 +288,25 @@ impl Parse for ErrorAttr {
parse_comma_separated(input)
}
}
+
+impl TryFrom<ErrorAttr> for EnumAttr {
+ type Error = syn::Error;
+
+ fn try_from(error_attr: ErrorAttr) -> Result<Self, Self::Error> {
+ if error_attr.flat.is_some() {
+ Err(syn::Error::new(
+ Span::call_site(),
+ "flat attribute not valid for rich enum errors",
+ ))
+ } else if error_attr.with_try_read.is_some() {
+ Err(syn::Error::new(
+ Span::call_site(),
+ "with_try_read attribute not valid for rich enum errors",
+ ))
+ } else {
+ Ok(EnumAttr {
+ non_exhaustive: error_attr.non_exhaustive,
+ })
+ }
+ }
+}