/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! # Attribute definitions for a `InterfaceCollector`. //! //! This module provides some conveniences for working with attribute definitions //! from WebIDL. When encountering a weedle `ExtendedAttribute` node, use `TryFrom` //! to convert it into an [`Attribute`] representing one of the attributes that we //! support. You can also use the [`parse_attributes`] function to parse an //! `ExtendedAttributeList` into a vec of same. //! //! We only support a small number of attributes, so it's manageable to have them //! all handled by a single abstraction. This might need to be refactored in future //! if we grow significantly more complicated attribute handling.
use anyhow::{bail, Result}; use uniffi_meta::{Checksum, ExternalKind, ObjectImpl};
/// Represents an attribute parsed from UDL, like `[ByRef]` or `[Throws]`. /// /// This is a convenience enum for parsing UDL attributes and erroring out if we encounter /// any unsupported ones. These don't convert directly into parts of a `InterfaceCollector`, but /// may influence the properties of things like functions and arguments. #[derive(Debug, Clone, Checksum)] pub(super) enum Attribute {
ByRef, Enum,
Error,
Name(String),
SelfType(SelfType),
Throws(String),
Traits(Vec<String>), // `[External="crate_name"]` - We can `use crate_name::...` for the type.
External {
crate_name: String,
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,
}
/// Parse a weedle `ExtendedAttributeList` into a list of `Attribute`s, /// erroring out on duplicates. fn parse_attributes<F>(
weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
validator: F,
) -> Result<Vec<Attribute>> where
F: Fn(&Attribute) -> Result<()>,
{ let attrs = &weedle_attributes.body.list;
letmut hash_set = std::collections::HashSet::new(); for attr in attrs { if !hash_set.insert(attr) {
anyhow::bail!("Duplicated ExtendedAttribute: {:?}", attr);
}
}
let attrs = attrs
.iter()
.map(Attribute::try_from)
.collect::<Result<Vec<_>, _>>()?;
for attr in &attrs {
validator(attr)?;
}
Ok(attrs)
}
/// Attributes that can be attached to an `enum` definition in the UDL. #[derive(Debug, Clone, Checksum, Default)] pub(super) struct EnumAttributes(Vec<Attribute>);
impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for EnumAttributes { type Error = anyhow::Error; fn try_from(
weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
) -> Result<Self, Self::Error> { 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))
}
}
impl<T: TryInto<EnumAttributes, Error = anyhow::Error>> TryFrom<Option<T>> for EnumAttributes { type Error = anyhow::Error; fn try_from(value: Option<T>) -> Result<Self, Self::Error> { match value {
None => Ok(Default::default()),
Some(v) => v.try_into(),
}
}
}
/// Represents UDL attributes that might appear on a function. /// /// 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<Attribute>);
impl FunctionAttributes { pub(super) fn get_throws_err(&self) -> Option<&str> { self.0.iter().find_map(|attr| match attr { // This will hopefully return a helpful compilation error // if the error is not defined.
Attribute::Throws(inner) => Some(inner.as_ref()),
_ => None,
})
}
impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for FunctionAttributes { type Error = anyhow::Error; fn try_from(
weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
) -> Result<Self, Self::Error> { let attrs = parse_attributes(weedle_attributes, |attr| match attr {
Attribute::Throws(_) | Attribute::Async => Ok(()),
_ => bail!(format!("{attr:?} not supported for functions")),
})?;
Ok(Self(attrs))
}
}
impl<T: TryInto<FunctionAttributes, Error = anyhow::Error>> TryFrom<Option<T>> for FunctionAttributes
{ type Error = anyhow::Error; fn try_from(value: Option<T>) -> Result<Self, Self::Error> { match value {
None => Ok(Default::default()),
Some(v) => v.try_into(),
}
}
}
/// Represents UDL attributes that might appear on a function argument. /// /// This supports the `[ByRef]` attribute for arguments that should be passed /// by reference in the generated Rust scaffolding. #[derive(Debug, Clone, Checksum, Default)] pub(super) struct ArgumentAttributes(Vec<Attribute>);
impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for InterfaceAttributes { type Error = anyhow::Error; fn try_from(
weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
) -> Result<Self, Self::Error> { let attrs = parse_attributes(weedle_attributes, |attr| match attr {
Attribute::Enum => Ok(()),
Attribute::Error => Ok(()),
Attribute::Trait => Ok(()),
Attribute::WithForeign => Ok(()),
Attribute::Traits(_) => Ok(()),
_ => bail!(format!("{attr:?} not supported for interface definition")),
})?; if attrs.iter().any(|a| matches!(a, Attribute::Enum)) && attrs.len() != 1 { // If `[Enum]` is specified it must be the only attribute.
bail!("conflicting attributes on interface definition");
}
Ok(Self(attrs))
}
}
impl<T: TryInto<InterfaceAttributes, Error = anyhow::Error>> TryFrom<Option<T>> for InterfaceAttributes
{ type Error = anyhow::Error; fn try_from(value: Option<T>) -> Result<Self, Self::Error> { match value {
None => Ok(Default::default()),
Some(v) => v.try_into(),
}
}
}
/// Represents UDL attributes that might appear on a constructor. /// /// This supports the `[Throws=ErrorName]` attribute for constructors that can produce /// an error, and the `[Name=MethodName]` for non-default constructors. #[derive(Debug, Clone, Checksum, Default)] pub(super) struct ConstructorAttributes(Vec<Attribute>);
impl ConstructorAttributes { pub(super) fn get_throws_err(&self) -> Option<&str> { self.0.iter().find_map(|attr| match attr { // This will hopefully return a helpful compilation error // if the error is not defined.
Attribute::Throws(inner) => Some(inner.as_ref()),
_ => None,
})
}
impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for ConstructorAttributes { type Error = anyhow::Error; fn try_from(
weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
) -> Result<Self, Self::Error> { 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))
}
}
/// Represents UDL attributes that might appear on a method. /// /// This supports the `[Throws=ErrorName]` attribute for methods that can produce /// an error, and the `[Self=ByArc]` attribute for methods that take `Arc<Self>` as receiver. #[derive(Debug, Clone, Checksum, Default)] pub(super) struct MethodAttributes(Vec<Attribute>);
impl MethodAttributes { pub(super) fn get_throws_err(&self) -> Option<&str> { self.0.iter().find_map(|attr| match attr { // This will hopefully return a helpful compilation error // if the error is not defined.
Attribute::Throws(inner) => Some(inner.as_ref()),
_ => None,
})
}
impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for MethodAttributes { type Error = anyhow::Error; fn try_from(
weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
) -> Result<Self, Self::Error> { let attrs = parse_attributes(weedle_attributes, |attr| match attr {
Attribute::SelfType(_) | Attribute::Throws(_) | Attribute::Async => Ok(()),
_ => bail!(format!("{attr:?} not supported for methods")),
})?;
Ok(Self(attrs))
}
}
impl<T: TryInto<MethodAttributes, Error = anyhow::Error>> TryFrom<Option<T>> for MethodAttributes { type Error = anyhow::Error; fn try_from(value: Option<T>) -> Result<Self, Self::Error> { match value {
None => Ok(Default::default()),
Some(v) => v.try_into(),
}
}
}
/// Represents the different possible types of method call receiver. /// /// Actually we only support one of these right now, `[Self=ByArc]`. /// We might add more in future, e.g. a `[Self=ByRef]` if there are cases /// where we need to force the receiver to be taken by reference. #[derive(Debug, Clone, Checksum)] pub(super) enum SelfType {
ByArc, // Method receiver is `Arc<Self>`.
}
/// Represents UDL attributes that might appear on a typedef /// /// This supports the `[External="crate_name"]` and `[Custom]` attributes for types. #[derive(Debug, Clone, Checksum, Default)] pub(super) struct TypedefAttributes(Vec<Attribute>);
pub(super) fn external_tagged(&self) -> Option<bool> { // 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,
})
}
}
impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for TypedefAttributes { type Error = anyhow::Error; fn try_from(
weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
) -> Result<Self, Self::Error> { let attrs = parse_attributes(weedle_attributes, |attr| match attr {
Attribute::External { .. } | Attribute::Custom | Attribute::Rust { .. } => Ok(()),
_ => bail!(format!("{attr:?} not supported for typedefs")),
})?;
Ok(Self(attrs))
}
}
impl<T: TryInto<TypedefAttributes, Error = anyhow::Error>> TryFrom<Option<T>> for TypedefAttributes
{ type Error = anyhow::Error; fn try_from(value: Option<T>) -> Result<Self, Self::Error> { match value {
None => Ok(Default::default()),
Some(v) => v.try_into(),
}
}
}
#[cfg(test)] mod test { usesuper::*; use weedle::Parse;
#[test] fn test_byref() -> Result<()> { let (_, node) = weedle::attribute::ExtendedAttribute::parse("ByRef").unwrap(); let attr = Attribute::try_from(&node)?;
assert!(matches!(attr, Attribute::ByRef));
Ok(())
}
#[test] fn test_enum() -> Result<()> { let (_, node) = weedle::attribute::ExtendedAttribute::parse("Enum").unwrap(); let attr = Attribute::try_from(&node)?;
assert!(matches!(attr, Attribute::Enum));
assert!(attr.is_enum());
Ok(())
}
#[test] fn test_error() -> Result<()> { let (_, node) = weedle::attribute::ExtendedAttribute::parse("Error").unwrap(); let attr = Attribute::try_from(&node)?;
assert!(matches!(attr, Attribute::Error));
assert!(attr.is_error());
Ok(())
}
#[test] fn test_name() -> Result<()> { let (_, node) = weedle::attribute::ExtendedAttribute::parse("Name=Value").unwrap(); let attr = Attribute::try_from(&node)?;
assert!(matches!(attr, Attribute::Name(nm) if nm == "Value"));
let (_, node) = weedle::attribute::ExtendedAttribute::parse("Name").unwrap(); let err = Attribute::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "ExtendedAttributeNoArgs not supported: \"Name\""
);
Ok(())
}
#[test] fn test_selftype() -> Result<()> { let (_, node) = weedle::attribute::ExtendedAttribute::parse("Self=ByArc").unwrap(); let attr = Attribute::try_from(&node)?;
assert!(matches!(attr, Attribute::SelfType(SelfType::ByArc))); let (_, node) = weedle::attribute::ExtendedAttribute::parse("Self=ByMistake").unwrap(); let err = Attribute::try_from(&node).unwrap_err();
assert_eq!(err.to_string(), "Unsupported Self Type: \"ByMistake\"");
Ok(())
}
#[test] fn test_trait() -> Result<()> { let (_, node) = weedle::attribute::ExtendedAttribute::parse("Trait").unwrap(); let attr = Attribute::try_from(&node)?;
assert!(matches!(attr, Attribute::Trait));
Ok(())
}
#[test] fn test_throws() -> Result<()> { let (_, node) = weedle::attribute::ExtendedAttribute::parse("Throws=Name").unwrap(); let attr = Attribute::try_from(&node)?;
assert!(matches!(attr, Attribute::Throws(nm) if nm == "Name"));
let (_, node) = weedle::attribute::ExtendedAttribute::parse("Throws").unwrap(); let err = Attribute::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "ExtendedAttributeNoArgs not supported: \"Throws\""
);
Ok(())
}
#[test] fn test_unsupported() { let (_, node) =
weedle::attribute::ExtendedAttribute::parse("UnsupportedAttribute").unwrap(); let err = Attribute::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "ExtendedAttributeNoArgs not supported: \"UnsupportedAttribute\""
);
let (_, node) =
weedle::attribute::ExtendedAttribute::parse("Unsupported=Attribute").unwrap(); let err = Attribute::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "Attribute identity Identifier not supported: \"Unsupported\""
);
}
#[test] fn test_other_attributes_not_supported_for_enums() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Error, ByRef]").unwrap(); let err = EnumAttributes::try_from(&node).unwrap_err();
assert_eq!(err.to_string(), "ByRef not supported for enums");
}
#[test] 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] fn test_other_attributes_not_supported_for_functions() { let (_, node) =
weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, ByRef]").unwrap(); let err = FunctionAttributes::try_from(&node).unwrap_err();
assert_eq!(err.to_string(), "ByRef not supported for functions");
let (_, node) =
weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, Self=ByArc]").unwrap(); let err = FunctionAttributes::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "SelfType(ByArc) not supported for functions"
);
}
#[test] fn test_method_attributes() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Throws=Error]").unwrap(); 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] fn test_constructor_attributes() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Throws=Error]").unwrap(); let attrs = ConstructorAttributes::try_from(&node).unwrap();
assert!(matches!(attrs.get_throws_err(), Some("Error")));
assert!(attrs.get_name().is_none());
let (_, node) =
weedle::attribute::ExtendedAttributeList::parse("[Name=MyFactory]").unwrap(); let attrs = ConstructorAttributes::try_from(&node).unwrap();
assert!(attrs.get_throws_err().is_none());
assert!(matches!(attrs.get_name(), Some("MyFactory")));
let (_, node) =
weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, Name=MyFactory]")
.unwrap(); 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] fn test_other_attributes_not_supported_for_constructors() { let (_, node) =
weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, ByRef]").unwrap(); let err = ConstructorAttributes::try_from(&node).unwrap_err();
assert_eq!(err.to_string(), "ByRef not supported for constructors");
let (_, node) =
weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, Self=ByArc]").unwrap(); let err = ConstructorAttributes::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "SelfType(ByArc) not supported for constructors"
);
}
#[test] fn test_byref_attribute() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[ByRef]").unwrap(); let attrs = ArgumentAttributes::try_from(&node).unwrap();
assert!(attrs.by_ref());
let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap(); let attrs = ArgumentAttributes::try_from(&node).unwrap();
assert!(!attrs.by_ref());
}
#[test] fn test_other_attributes_not_supported_for_arguments() { let (_, node) =
weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, ByRef]").unwrap(); let err = ArgumentAttributes::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "Throws(\"Error\") not supported for arguments"
);
}
#[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().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().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_on_interface() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Enum]").unwrap(); let attrs = InterfaceAttributes::try_from(&node).unwrap();
assert!(attrs.contains_enum_attr());
let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap(); let attrs = InterfaceAttributes::try_from(&node).unwrap();
assert!(!attrs.contains_enum_attr());
let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait]").unwrap(); let attrs = InterfaceAttributes::try_from(&node).unwrap();
assert!(!attrs.contains_enum_attr());
let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait, Enum]").unwrap(); let err = InterfaceAttributes::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "conflicting attributes on interface definition"
);
}
// 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(); let err = InterfaceAttributes::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "ByRef not supported for interface definition"
);
}
#[test] fn test_typedef_attribute() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Custom]").unwrap(); let attrs = TypedefAttributes::try_from(&node).unwrap();
assert!(attrs.is_custom());
let (_, node) =
weedle::attribute::ExtendedAttributeList::parse("[External=crate_name]").unwrap(); let attrs = TypedefAttributes::try_from(&node).unwrap();
assert!(!attrs.is_custom());
assert_eq!(attrs.get_crate_name(), "crate_name");
let (_, node) =
weedle::attribute::ExtendedAttributeList::parse("[ExternalInterface=crate_name ]")
.unwrap(); let attrs = TypedefAttributes::try_from(&node).unwrap();
assert!(!attrs.is_custom());
assert_eq!(attrs.get_crate_name(), "crate_name");
}
#[test] fn test_typedef_attributes_malformed() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Custom=foo]").unwrap(); let err = TypedefAttributes::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "Attribute identity Identifier not supported: \"Custom\""
);
let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[External]").unwrap(); let err = TypedefAttributes::try_from(&node).unwrap_err();
assert_eq!(
err.to_string(), "ExtendedAttributeNoArgs not supported: \"External\""
);
}
#[test] fn test_other_attributes_not_supported_for_typedef() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[ByRef]").unwrap(); let err = TypedefAttributes::try_from(&node).unwrap_err();
assert_eq!(err.to_string(), "ByRef not supported for typedefs");
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-06-18)
¤
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.