From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- third_party/rust/uniffi_udl/src/attributes.rs | 199 +++++++++++++++++++++++--- 1 file changed, 182 insertions(+), 17 deletions(-) (limited to 'third_party/rust/uniffi_udl/src/attributes.rs') diff --git a/third_party/rust/uniffi_udl/src/attributes.rs b/third_party/rust/uniffi_udl/src/attributes.rs index f06b4f29c1..7bb05808c4 100644 --- a/third_party/rust/uniffi_udl/src/attributes.rs +++ b/third_party/rust/uniffi_udl/src/attributes.rs @@ -37,10 +37,29 @@ pub(super) enum Attribute { kind: ExternalKind, export: bool, }, + Rust { + kind: RustKind, + }, // Custom type on the scaffolding side Custom, // The interface described is implemented as a trait. Trait, + // Modifies `Trait` to enable foreign implementations (callback interfaces) + WithForeign, + Async, + NonExhaustive, +} + +// A type defined in Rust via procmacros but which should be available +// in UDL. +#[derive(Debug, Copy, Clone, Checksum)] +pub(super) enum RustKind { + Object, + CallbackTrait, + Trait, + Record, + Enum, + CallbackInterface, } impl Attribute { @@ -67,6 +86,9 @@ impl TryFrom<&weedle::attribute::ExtendedAttribute<'_>> for Attribute { "Error" => Ok(Attribute::Error), "Custom" => Ok(Attribute::Custom), "Trait" => Ok(Attribute::Trait), + "WithForeign" => Ok(Attribute::WithForeign), + "Async" => Ok(Attribute::Async), + "NonExhaustive" => Ok(Attribute::NonExhaustive), _ => anyhow::bail!("ExtendedAttributeNoArgs not supported: {:?}", (attr.0).0), }, // Matches assignment-style attributes like ["Throws=Error"] @@ -95,6 +117,19 @@ impl TryFrom<&weedle::attribute::ExtendedAttribute<'_>> for Attribute { kind: ExternalKind::Interface, export: true, }), + "ExternalTrait" => Ok(Attribute::External { + crate_name: name_from_id_or_string(&identity.rhs), + kind: ExternalKind::Trait, + export: false, + }), + "ExternalTraitExport" => Ok(Attribute::External { + crate_name: name_from_id_or_string(&identity.rhs), + kind: ExternalKind::Trait, + export: true, + }), + "Rust" => Ok(Attribute::Rust { + kind: rust_kind_from_id_or_string(&identity.rhs)?, + }), _ => anyhow::bail!( "Attribute identity Identifier not supported: {:?}", identity.lhs_identifier.0 @@ -130,6 +165,26 @@ fn name_from_id_or_string(nm: &weedle::attribute::IdentifierOrString<'_>) -> Str } } +fn rust_kind_from_id_or_string(nm: &weedle::attribute::IdentifierOrString<'_>) -> Result { + Ok(match nm { + weedle::attribute::IdentifierOrString::String(str_lit) => match str_lit.0 { + // support names which match either procmacro or udl + "interface" => RustKind::Object, + "object" => RustKind::Object, + "record" => RustKind::Record, + "dictionary" => RustKind::Record, + "enum" => RustKind::Enum, + "trait" => RustKind::Trait, + "callback" => RustKind::CallbackInterface, + "trait_with_foreign" => RustKind::CallbackTrait, + _ => anyhow::bail!("Unknown `[Rust=]` kind {:?}", str_lit.0), + }, + weedle::attribute::IdentifierOrString::Identifier(_) => { + anyhow::bail!("Expected string attribute value, got identifier") + } + }) +} + /// Parse a weedle `ExtendedAttributeList` into a list of `Attribute`s, /// erroring out on duplicates. fn parse_attributes( @@ -161,7 +216,6 @@ where } /// Attributes that can be attached to an `enum` definition in the UDL. -/// There's only one case here: using `[Error]` to mark an enum as an error class. #[derive(Debug, Clone, Checksum, Default)] pub(super) struct EnumAttributes(Vec); @@ -169,6 +223,12 @@ impl EnumAttributes { pub fn contains_error_attr(&self) -> bool { self.0.iter().any(|attr| attr.is_error()) } + + pub fn contains_non_exhaustive_attr(&self) -> bool { + self.0 + .iter() + .any(|attr| matches!(attr, Attribute::NonExhaustive)) + } } impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for EnumAttributes { @@ -178,6 +238,10 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for EnumAttributes { ) -> Result { let attrs = parse_attributes(weedle_attributes, |attr| match attr { Attribute::Error => Ok(()), + Attribute::NonExhaustive => Ok(()), + // Allow `[Enum]`, since we may be parsing an attribute list from an interface with the + // `[Enum]` attribute. + Attribute::Enum => Ok(()), _ => bail!(format!("{attr:?} not supported for enums")), })?; Ok(Self(attrs)) @@ -196,8 +260,9 @@ impl> TryFrom> for E /// Represents UDL attributes that might appear on a function. /// -/// This supports the `[Throws=ErrorName]` attribute for functions that -/// can produce an error. +/// This supports: +/// * `[Throws=ErrorName]` attribute for functions that can produce an error. +/// * `[Async] for async functions #[derive(Debug, Clone, Checksum, Default)] pub(super) struct FunctionAttributes(Vec); @@ -210,6 +275,10 @@ impl FunctionAttributes { _ => None, }) } + + pub(super) fn is_async(&self) -> bool { + self.0.iter().any(|attr| matches!(attr, Attribute::Async)) + } } impl FromIterator for FunctionAttributes { @@ -224,7 +293,7 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for FunctionAttribut weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>, ) -> Result { let attrs = parse_attributes(weedle_attributes, |attr| match attr { - Attribute::Throws(_) => Ok(()), + Attribute::Throws(_) | Attribute::Async => Ok(()), _ => bail!(format!("{attr:?} not supported for functions")), })?; Ok(Self(attrs)) @@ -294,12 +363,25 @@ impl InterfaceAttributes { self.0.iter().any(|attr| attr.is_error()) } - pub fn object_impl(&self) -> ObjectImpl { - if self.0.iter().any(|attr| matches!(attr, Attribute::Trait)) { - ObjectImpl::Trait - } else { - ObjectImpl::Struct - } + pub fn contains_trait(&self) -> bool { + self.0.iter().any(|attr| matches!(attr, Attribute::Trait)) + } + + pub fn contains_with_foreign(&self) -> bool { + self.0 + .iter() + .any(|attr| matches!(attr, Attribute::WithForeign)) + } + + pub fn object_impl(&self) -> Result { + Ok( + match (self.contains_trait(), self.contains_with_foreign()) { + (true, true) => ObjectImpl::CallbackTrait, + (true, false) => ObjectImpl::Trait, + (false, false) => ObjectImpl::Struct, + (false, true) => bail!("WithForeign can't be specified without Trait"), + }, + ) } pub fn get_traits(&self) -> Vec { self.0 @@ -321,6 +403,7 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for InterfaceAttribu Attribute::Enum => Ok(()), Attribute::Error => Ok(()), Attribute::Trait => Ok(()), + Attribute::WithForeign => Ok(()), Attribute::Traits(_) => Ok(()), _ => bail!(format!("{attr:?} not supported for interface definition")), })?; @@ -373,6 +456,10 @@ impl ConstructorAttributes { _ => None, }) } + + pub(super) fn is_async(&self) -> bool { + self.0.iter().any(|attr| matches!(attr, Attribute::Async)) + } } impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for ConstructorAttributes { @@ -383,6 +470,7 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for ConstructorAttri let attrs = parse_attributes(weedle_attributes, |attr| match attr { Attribute::Throws(_) => Ok(()), Attribute::Name(_) => Ok(()), + Attribute::Async => Ok(()), _ => bail!(format!("{attr:?} not supported for constructors")), })?; Ok(Self(attrs)) @@ -406,6 +494,10 @@ impl MethodAttributes { }) } + pub(super) fn is_async(&self) -> bool { + self.0.iter().any(|attr| matches!(attr, Attribute::Async)) + } + pub(super) fn get_self_by_arc(&self) -> bool { self.0 .iter() @@ -425,8 +517,7 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for MethodAttributes weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>, ) -> Result { let attrs = parse_attributes(weedle_attributes, |attr| match attr { - Attribute::SelfType(_) => Ok(()), - Attribute::Throws(_) => Ok(()), + Attribute::SelfType(_) | Attribute::Throws(_) | Attribute::Async => Ok(()), _ => bail!(format!("{attr:?} not supported for methods")), })?; Ok(Self(attrs)) @@ -498,10 +589,18 @@ impl TypedefAttributes { }) } + pub(super) fn rust_kind(&self) -> Option { + self.0.iter().find_map(|attr| match attr { + Attribute::Rust { kind, .. } => Some(*kind), + _ => None, + }) + } + pub(super) fn external_tagged(&self) -> Option { // If it was "exported" via a proc-macro the FfiConverter was not tagged. self.0.iter().find_map(|attr| match attr { Attribute::External { export, .. } => Some(!*export), + Attribute::Rust { .. } => Some(false), _ => None, }) } @@ -513,7 +612,7 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for TypedefAttribute weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>, ) -> Result { let attrs = parse_attributes(weedle_attributes, |attr| match attr { - Attribute::External { .. } | Attribute::Custom => Ok(()), + Attribute::External { .. } | Attribute::Custom | Attribute::Rust { .. } => Ok(()), _ => bail!(format!("{attr:?} not supported for typedefs")), })?; Ok(Self(attrs)) @@ -641,14 +740,22 @@ mod test { } #[test] - fn test_throws_attribute() { + fn test_function_attributes() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Throws=Error]").unwrap(); let attrs = FunctionAttributes::try_from(&node).unwrap(); assert!(matches!(attrs.get_throws_err(), Some("Error"))); + assert!(!attrs.is_async()); let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap(); let attrs = FunctionAttributes::try_from(&node).unwrap(); assert!(attrs.get_throws_err().is_none()); + assert!(!attrs.is_async()); + + let (_, node) = + weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, Async]").unwrap(); + let attrs = FunctionAttributes::try_from(&node).unwrap(); + assert!(matches!(attrs.get_throws_err(), Some("Error"))); + assert!(attrs.is_async()); } #[test] @@ -673,22 +780,34 @@ mod test { let attrs = MethodAttributes::try_from(&node).unwrap(); assert!(!attrs.get_self_by_arc()); assert!(matches!(attrs.get_throws_err(), Some("Error"))); + assert!(!attrs.is_async()); let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap(); let attrs = MethodAttributes::try_from(&node).unwrap(); assert!(!attrs.get_self_by_arc()); assert!(attrs.get_throws_err().is_none()); + assert!(!attrs.is_async()); let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Self=ByArc, Throws=Error]").unwrap(); let attrs = MethodAttributes::try_from(&node).unwrap(); assert!(attrs.get_self_by_arc()); assert!(attrs.get_throws_err().is_some()); + assert!(!attrs.is_async()); + + let (_, node) = + weedle::attribute::ExtendedAttributeList::parse("[Self=ByArc, Throws=Error, Async]") + .unwrap(); + let attrs = MethodAttributes::try_from(&node).unwrap(); + assert!(attrs.get_self_by_arc()); + assert!(attrs.get_throws_err().is_some()); + assert!(attrs.is_async()); let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Self=ByArc]").unwrap(); let attrs = MethodAttributes::try_from(&node).unwrap(); assert!(attrs.get_self_by_arc()); assert!(attrs.get_throws_err().is_none()); + assert!(!attrs.is_async()); } #[test] @@ -710,6 +829,11 @@ mod test { let attrs = ConstructorAttributes::try_from(&node).unwrap(); assert!(matches!(attrs.get_throws_err(), Some("Error"))); assert!(matches!(attrs.get_name(), Some("MyFactory"))); + assert!(!attrs.is_async()); + + let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Async]").unwrap(); + let attrs = ConstructorAttributes::try_from(&node).unwrap(); + assert!(attrs.is_async()); } #[test] @@ -754,15 +878,24 @@ mod test { fn test_trait_attribute() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait]").unwrap(); let attrs = InterfaceAttributes::try_from(&node).unwrap(); - assert_eq!(attrs.object_impl(), ObjectImpl::Trait); + assert_eq!(attrs.object_impl().unwrap(), ObjectImpl::Trait); + + let (_, node) = + weedle::attribute::ExtendedAttributeList::parse("[Trait, WithForeign]").unwrap(); + let attrs = InterfaceAttributes::try_from(&node).unwrap(); + assert_eq!(attrs.object_impl().unwrap(), ObjectImpl::CallbackTrait); let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap(); let attrs = InterfaceAttributes::try_from(&node).unwrap(); - assert_eq!(attrs.object_impl(), ObjectImpl::Struct); + assert_eq!(attrs.object_impl().unwrap(), ObjectImpl::Struct); + + let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[WithForeign]").unwrap(); + let attrs = InterfaceAttributes::try_from(&node).unwrap(); + assert!(attrs.object_impl().is_err()) } #[test] - fn test_enum_attribute() { + fn test_enum_attribute_on_interface() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Enum]").unwrap(); let attrs = InterfaceAttributes::try_from(&node).unwrap(); assert!(matches!(attrs.contains_enum_attr(), true)); @@ -783,6 +916,38 @@ mod test { ); } + // Test parsing attributes for enum definitions + #[test] + fn test_enum_attributes() { + let (_, node) = + weedle::attribute::ExtendedAttributeList::parse("[Error, NonExhaustive]").unwrap(); + let attrs = EnumAttributes::try_from(&node).unwrap(); + assert!(attrs.contains_error_attr()); + assert!(attrs.contains_non_exhaustive_attr()); + + let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait]").unwrap(); + let err = EnumAttributes::try_from(&node).unwrap_err(); + assert_eq!(err.to_string(), "Trait not supported for enums"); + } + + // Test parsing attributes for interface definitions with the `[Enum]` attribute + #[test] + fn test_enum_attributes_from_interface() { + let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Enum]").unwrap(); + assert!(EnumAttributes::try_from(&node).is_ok()); + + let (_, node) = + weedle::attribute::ExtendedAttributeList::parse("[Enum, Error, NonExhaustive]") + .unwrap(); + let attrs = EnumAttributes::try_from(&node).unwrap(); + assert!(attrs.contains_error_attr()); + assert!(attrs.contains_non_exhaustive_attr()); + + let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Enum, Trait]").unwrap(); + let err = EnumAttributes::try_from(&node).unwrap_err(); + assert_eq!(err.to_string(), "Trait not supported for enums"); + } + #[test] fn test_other_attributes_not_supported_for_interfaces() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait, ByRef]").unwrap(); -- cgit v1.2.3