1use anyhow::{bail, Result};
18use uniffi_meta::{Checksum, ObjectImpl};
19
20#[derive(Debug, Clone, Checksum)]
26pub(super) enum Attribute {
27 ByRef,
28 Enum,
29 Error,
30 Name(String),
31 SelfType(SelfType),
32 Throws(String),
33 Traits(Vec<String>),
34 External { crate_name: String },
36 Remote,
37 Custom { crate_name: Option<String> },
39 Trait,
41 WithForeign,
43 Async,
44 NonExhaustive,
45}
46
47impl Attribute {
48 pub fn is_error(&self) -> bool {
49 matches!(self, Attribute::Error)
50 }
51 pub fn is_enum(&self) -> bool {
52 matches!(self, Attribute::Enum)
53 }
54}
55
56impl TryFrom<&weedle::attribute::ExtendedAttribute<'_>> for Attribute {
59 type Error = anyhow::Error;
60 fn try_from(
61 weedle_attribute: &weedle::attribute::ExtendedAttribute<'_>,
62 ) -> Result<Self, anyhow::Error> {
63 match weedle_attribute {
64 weedle::attribute::ExtendedAttribute::NoArgs(attr) => match (attr.0).0 {
66 "ByRef" => Ok(Attribute::ByRef),
67 "Enum" => Ok(Attribute::Enum),
68 "Error" => Ok(Attribute::Error),
69 "Custom" => Ok(Attribute::Custom { crate_name: None }),
70 "Trait" => Ok(Attribute::Trait),
71 "WithForeign" => Ok(Attribute::WithForeign),
72 "Async" => Ok(Attribute::Async),
73 "NonExhaustive" => Ok(Attribute::NonExhaustive),
74 "Remote" => Ok(Attribute::Remote),
75 _ => anyhow::bail!("ExtendedAttributeNoArgs not supported: {:?}", (attr.0).0),
76 },
77 weedle::attribute::ExtendedAttribute::Ident(identity) => {
79 match identity.lhs_identifier.0 {
80 "Name" => Ok(Attribute::Name(name_from_id_or_string(&identity.rhs))),
81 "Throws" => Ok(Attribute::Throws(name_from_id_or_string(&identity.rhs))),
82 "Self" => Ok(Attribute::SelfType(SelfType::try_from(&identity.rhs)?)),
83 "External" => Ok(Attribute::External {
84 crate_name: name_from_id_or_string(&identity.rhs),
85 }),
86 "Custom" => Ok(Attribute::Custom {
87 crate_name: Some(name_from_id_or_string(&identity.rhs)),
88 }),
89 _ => anyhow::bail!(
90 "Attribute identity Identifier not supported: {:?}",
91 identity.lhs_identifier.0
92 ),
93 }
94 }
95 weedle::attribute::ExtendedAttribute::IdentList(attr_list) => {
96 match attr_list.identifier.0 {
97 "Traits" => Ok(Attribute::Traits(
98 attr_list
99 .list
100 .body
101 .list
102 .iter()
103 .map(|i| i.0.to_string())
104 .collect(),
105 )),
106 _ => anyhow::bail!(
107 "Attribute identity list not supported: {:?}",
108 attr_list.identifier.0
109 ),
110 }
111 }
112 _ => anyhow::bail!("Attribute not supported: {:?}", weedle_attribute),
113 }
114 }
115}
116
117fn name_from_id_or_string(nm: &weedle::attribute::IdentifierOrString<'_>) -> String {
118 match nm {
119 weedle::attribute::IdentifierOrString::Identifier(identifier) => identifier.0.to_string(),
120 weedle::attribute::IdentifierOrString::String(str_lit) => str_lit.0.to_string(),
121 }
122}
123
124fn parse_attributes<F>(
127 weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
128 validator: F,
129) -> Result<Vec<Attribute>>
130where
131 F: Fn(&Attribute) -> Result<()>,
132{
133 let attrs = &weedle_attributes.body.list;
134
135 let mut hash_set = std::collections::HashSet::new();
136 for attr in attrs {
137 if !hash_set.insert(attr) {
138 anyhow::bail!("Duplicated ExtendedAttribute: {:?}", attr);
139 }
140 }
141
142 let attrs = attrs
143 .iter()
144 .map(Attribute::try_from)
145 .collect::<Result<Vec<_>, _>>()?;
146
147 for attr in &attrs {
148 validator(attr)?;
149 }
150
151 Ok(attrs)
152}
153
154#[derive(Debug, Clone, Checksum, Default)]
156pub(super) struct DictionaryAttributes(Vec<Attribute>);
157
158impl DictionaryAttributes {
159 pub fn contains_remote(&self) -> bool {
160 self.0.iter().any(|attr| matches!(attr, Attribute::Remote))
161 }
162
163 pub fn get_uniffi_traits(&self) -> Vec<String> {
164 self.0
165 .iter()
166 .find_map(|attr| match attr {
167 Attribute::Traits(inner) => Some(inner.clone()),
168 _ => None,
169 })
170 .unwrap_or_default()
171 }
172}
173
174impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for DictionaryAttributes {
175 type Error = anyhow::Error;
176 fn try_from(
177 weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
178 ) -> Result<Self, Self::Error> {
179 let attrs = parse_attributes(weedle_attributes, |attr| match attr {
180 Attribute::Remote => Ok(()),
181 Attribute::Traits(_) => Ok(()),
182 _ => bail!(format!("{attr:?} not supported for dictionaries")),
183 })?;
184 Ok(Self(attrs))
185 }
186}
187
188impl<T: TryInto<DictionaryAttributes, Error = anyhow::Error>> TryFrom<Option<T>>
189 for DictionaryAttributes
190{
191 type Error = anyhow::Error;
192 fn try_from(value: Option<T>) -> Result<Self, Self::Error> {
193 match value {
194 None => Ok(Default::default()),
195 Some(v) => v.try_into(),
196 }
197 }
198}
199
200#[derive(Debug, Clone, Checksum, Default)]
202pub(super) struct EnumAttributes(Vec<Attribute>);
203
204impl EnumAttributes {
205 pub fn contains_error_attr(&self) -> bool {
206 self.0.iter().any(|attr| attr.is_error())
207 }
208
209 pub fn contains_non_exhaustive_attr(&self) -> bool {
210 self.0
211 .iter()
212 .any(|attr| matches!(attr, Attribute::NonExhaustive))
213 }
214
215 pub fn contains_remote(&self) -> bool {
216 self.0.iter().any(|attr| matches!(attr, Attribute::Remote))
217 }
218
219 pub fn get_uniffi_traits(&self) -> Vec<String> {
220 self.0
221 .iter()
222 .find_map(|attr| match attr {
223 Attribute::Traits(inner) => Some(inner.clone()),
224 _ => None,
225 })
226 .unwrap_or_default()
227 }
228}
229
230impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for EnumAttributes {
231 type Error = anyhow::Error;
232 fn try_from(
233 weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
234 ) -> Result<Self, Self::Error> {
235 let attrs = parse_attributes(weedle_attributes, |attr| match attr {
236 Attribute::Error => Ok(()),
237 Attribute::NonExhaustive => Ok(()),
238 Attribute::Remote => Ok(()),
239 Attribute::Enum => Ok(()),
242 Attribute::Traits(_) => Ok(()),
243 _ => bail!(format!("{attr:?} not supported for enums")),
244 })?;
245 Ok(Self(attrs))
246 }
247}
248
249impl<T: TryInto<EnumAttributes, Error = anyhow::Error>> TryFrom<Option<T>> for EnumAttributes {
250 type Error = anyhow::Error;
251 fn try_from(value: Option<T>) -> Result<Self, Self::Error> {
252 match value {
253 None => Ok(Default::default()),
254 Some(v) => v.try_into(),
255 }
256 }
257}
258
259#[derive(Debug, Clone, Checksum, Default)]
265pub(super) struct FunctionAttributes(Vec<Attribute>);
266
267impl FunctionAttributes {
268 pub(super) fn get_throws_err(&self) -> Option<&str> {
269 self.0.iter().find_map(|attr| match attr {
270 Attribute::Throws(inner) => Some(inner.as_ref()),
273 _ => None,
274 })
275 }
276
277 pub(super) fn is_async(&self) -> bool {
278 self.0.iter().any(|attr| matches!(attr, Attribute::Async))
279 }
280}
281
282impl FromIterator<Attribute> for FunctionAttributes {
283 fn from_iter<T: IntoIterator<Item = Attribute>>(iter: T) -> Self {
284 Self(Vec::from_iter(iter))
285 }
286}
287
288impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for FunctionAttributes {
289 type Error = anyhow::Error;
290 fn try_from(
291 weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
292 ) -> Result<Self, Self::Error> {
293 let attrs = parse_attributes(weedle_attributes, |attr| match attr {
294 Attribute::Throws(_) | Attribute::Async => Ok(()),
295 _ => bail!(format!("{attr:?} not supported for functions")),
296 })?;
297 Ok(Self(attrs))
298 }
299}
300
301impl<T: TryInto<FunctionAttributes, Error = anyhow::Error>> TryFrom<Option<T>>
302 for FunctionAttributes
303{
304 type Error = anyhow::Error;
305 fn try_from(value: Option<T>) -> Result<Self, Self::Error> {
306 match value {
307 None => Ok(Default::default()),
308 Some(v) => v.try_into(),
309 }
310 }
311}
312
313#[derive(Debug, Clone, Checksum, Default)]
318pub(super) struct ArgumentAttributes(Vec<Attribute>);
319
320impl ArgumentAttributes {
321 pub fn by_ref(&self) -> bool {
322 self.0.iter().any(|attr| matches!(attr, Attribute::ByRef))
323 }
324}
325
326impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for ArgumentAttributes {
327 type Error = anyhow::Error;
328 fn try_from(
329 weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
330 ) -> Result<Self, Self::Error> {
331 let attrs = parse_attributes(weedle_attributes, |attr| match attr {
332 Attribute::ByRef => Ok(()),
333 _ => bail!(format!("{attr:?} not supported for arguments")),
334 })?;
335 Ok(Self(attrs))
336 }
337}
338
339impl<T: TryInto<ArgumentAttributes, Error = anyhow::Error>> TryFrom<Option<T>>
340 for ArgumentAttributes
341{
342 type Error = anyhow::Error;
343 fn try_from(value: Option<T>) -> Result<Self, Self::Error> {
344 match value {
345 None => Ok(Default::default()),
346 Some(v) => v.try_into(),
347 }
348 }
349}
350
351#[derive(Debug, Clone, Checksum, Default)]
353pub(super) struct InterfaceAttributes(Vec<Attribute>);
354
355impl InterfaceAttributes {
356 pub fn contains_enum_attr(&self) -> bool {
357 self.0.iter().any(|attr| attr.is_enum())
358 }
359
360 pub fn contains_error_attr(&self) -> bool {
361 self.0.iter().any(|attr| attr.is_error())
362 }
363
364 pub fn contains_trait(&self) -> bool {
365 self.0.iter().any(|attr| matches!(attr, Attribute::Trait))
366 }
367
368 pub fn contains_remote(&self) -> bool {
369 self.0.iter().any(|attr| matches!(attr, Attribute::Remote))
370 }
371
372 pub fn contains_with_foreign(&self) -> bool {
373 self.0
374 .iter()
375 .any(|attr| matches!(attr, Attribute::WithForeign))
376 }
377
378 pub fn object_impl(&self) -> Result<ObjectImpl> {
379 Ok(
380 match (self.contains_trait(), self.contains_with_foreign()) {
381 (true, true) => ObjectImpl::CallbackTrait,
382 (true, false) => ObjectImpl::Trait,
383 (false, false) => ObjectImpl::Struct,
384 (false, true) => bail!("WithForeign can't be specified without Trait"),
385 },
386 )
387 }
388 pub fn get_traits(&self) -> Vec<String> {
389 self.0
390 .iter()
391 .find_map(|attr| match attr {
392 Attribute::Traits(inner) => Some(inner.clone()),
393 _ => None,
394 })
395 .unwrap_or_default()
396 }
397}
398
399impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for InterfaceAttributes {
400 type Error = anyhow::Error;
401 fn try_from(
402 weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
403 ) -> Result<Self, Self::Error> {
404 let attrs = parse_attributes(weedle_attributes, |attr| match attr {
405 Attribute::Enum => Ok(()),
406 Attribute::Error => Ok(()),
407 Attribute::Trait => Ok(()),
408 Attribute::WithForeign => Ok(()),
409 Attribute::Traits(_) => Ok(()),
410 Attribute::Remote => Ok(()),
411 _ => bail!(format!("{attr:?} not supported for interface definition")),
412 })?;
413 let ok_for_enum =
415 attrs.len() == 1 || attrs.iter().any(|a| matches!(a, Attribute::Traits(_)));
416 if attrs.iter().any(|a| matches!(a, Attribute::Enum)) && !ok_for_enum {
417 bail!("conflicting attributes on interface definition");
418 }
419 Ok(Self(attrs))
420 }
421}
422
423impl<T: TryInto<InterfaceAttributes, Error = anyhow::Error>> TryFrom<Option<T>>
424 for InterfaceAttributes
425{
426 type Error = anyhow::Error;
427 fn try_from(value: Option<T>) -> Result<Self, Self::Error> {
428 match value {
429 None => Ok(Default::default()),
430 Some(v) => v.try_into(),
431 }
432 }
433}
434
435#[derive(Debug, Clone, Checksum, Default)]
440pub(super) struct ConstructorAttributes(Vec<Attribute>);
441
442impl FromIterator<Attribute> for ConstructorAttributes {
443 fn from_iter<T: IntoIterator<Item = Attribute>>(iter: T) -> Self {
444 Self(Vec::from_iter(iter))
445 }
446}
447
448impl ConstructorAttributes {
449 pub(super) fn get_throws_err(&self) -> Option<&str> {
450 self.0.iter().find_map(|attr| match attr {
451 Attribute::Throws(inner) => Some(inner.as_ref()),
454 _ => None,
455 })
456 }
457
458 pub(super) fn get_name(&self) -> Option<&str> {
459 self.0.iter().find_map(|attr| match attr {
460 Attribute::Name(inner) => Some(inner.as_ref()),
461 _ => None,
462 })
463 }
464
465 pub(super) fn is_async(&self) -> bool {
466 self.0.iter().any(|attr| matches!(attr, Attribute::Async))
467 }
468}
469
470impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for ConstructorAttributes {
471 type Error = anyhow::Error;
472 fn try_from(
473 weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
474 ) -> Result<Self, Self::Error> {
475 let attrs = parse_attributes(weedle_attributes, |attr| match attr {
476 Attribute::Throws(_) => Ok(()),
477 Attribute::Name(_) => Ok(()),
478 Attribute::Async => Ok(()),
479 _ => bail!(format!("{attr:?} not supported for constructors")),
480 })?;
481 Ok(Self(attrs))
482 }
483}
484
485#[derive(Debug, Clone, Checksum, Default)]
490pub(super) struct MethodAttributes(Vec<Attribute>);
491
492impl MethodAttributes {
493 pub(super) fn get_throws_err(&self) -> Option<&str> {
494 self.0.iter().find_map(|attr| match attr {
495 Attribute::Throws(inner) => Some(inner.as_ref()),
498 _ => None,
499 })
500 }
501
502 pub(super) fn is_async(&self) -> bool {
503 self.0.iter().any(|attr| matches!(attr, Attribute::Async))
504 }
505
506 pub(super) fn get_self_by_arc(&self) -> bool {
507 self.0
508 .iter()
509 .any(|attr| matches!(attr, Attribute::SelfType(SelfType::ByArc)))
510 }
511}
512
513impl FromIterator<Attribute> for MethodAttributes {
514 fn from_iter<T: IntoIterator<Item = Attribute>>(iter: T) -> Self {
515 Self(Vec::from_iter(iter))
516 }
517}
518
519impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for MethodAttributes {
520 type Error = anyhow::Error;
521 fn try_from(
522 weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
523 ) -> Result<Self, Self::Error> {
524 let attrs = parse_attributes(weedle_attributes, |attr| match attr {
525 Attribute::SelfType(_) | Attribute::Throws(_) | Attribute::Async => Ok(()),
526 _ => bail!(format!("{attr:?} not supported for methods")),
527 })?;
528 Ok(Self(attrs))
529 }
530}
531
532impl<T: TryInto<MethodAttributes, Error = anyhow::Error>> TryFrom<Option<T>> for MethodAttributes {
533 type Error = anyhow::Error;
534 fn try_from(value: Option<T>) -> Result<Self, Self::Error> {
535 match value {
536 None => Ok(Default::default()),
537 Some(v) => v.try_into(),
538 }
539 }
540}
541
542#[derive(Debug, Clone, Checksum)]
548pub(super) enum SelfType {
549 ByArc, }
551
552impl TryFrom<&weedle::attribute::IdentifierOrString<'_>> for SelfType {
553 type Error = anyhow::Error;
554 fn try_from(nm: &weedle::attribute::IdentifierOrString<'_>) -> Result<Self, Self::Error> {
555 Ok(match nm {
556 weedle::attribute::IdentifierOrString::Identifier(identifier) => match identifier.0 {
557 "ByArc" => SelfType::ByArc,
558 _ => bail!("Unsupported Self Type: {:?}", identifier.0),
559 },
560 weedle::attribute::IdentifierOrString::String(_) => {
561 bail!("Unsupported Self Type: {:?}", nm)
562 }
563 })
564 }
565}
566
567#[derive(Debug, Clone, Checksum, Default)]
571pub(super) struct TypedefAttributes(Vec<Attribute>);
572
573impl TypedefAttributes {
574 pub(super) fn get_crate_name(&self) -> Option<String> {
575 self.0.iter().find_map(|attr| match attr {
576 Attribute::External { crate_name, .. } => Some(crate_name.clone()),
577 Attribute::Custom {
578 crate_name: Some(crate_name),
579 ..
580 } => Some(crate_name.clone()),
581 _ => None,
582 })
583 }
584
585 pub(super) fn is_custom(&self) -> bool {
586 self.0
587 .iter()
588 .any(|attr| matches!(attr, Attribute::Custom { .. }))
589 }
590}
591
592impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for TypedefAttributes {
593 type Error = anyhow::Error;
594 fn try_from(
595 weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>,
596 ) -> Result<Self, Self::Error> {
597 let attrs = parse_attributes(weedle_attributes, |attr| match attr {
598 Attribute::External { .. } | Attribute::Custom { .. } => Ok(()),
599 _ => bail!(format!("{attr:?} not supported for typedefs")),
600 })?;
601 if attrs.len() > 1 {
602 bail!("Can't be [Custom] and [External]");
603 }
604 Ok(Self(attrs))
605 }
606}
607
608impl<T: TryInto<TypedefAttributes, Error = anyhow::Error>> TryFrom<Option<T>>
609 for TypedefAttributes
610{
611 type Error = anyhow::Error;
612 fn try_from(value: Option<T>) -> Result<Self, Self::Error> {
613 match value {
614 None => Ok(Default::default()),
615 Some(v) => v.try_into(),
616 }
617 }
618}
619
620#[cfg(test)]
621mod test {
622 use super::*;
623 use weedle::Parse;
624
625 #[test]
626 fn test_byref() -> Result<()> {
627 let (_, node) = weedle::attribute::ExtendedAttribute::parse("ByRef").unwrap();
628 let attr = Attribute::try_from(&node)?;
629 assert!(matches!(attr, Attribute::ByRef));
630 Ok(())
631 }
632
633 #[test]
634 fn test_enum() -> Result<()> {
635 let (_, node) = weedle::attribute::ExtendedAttribute::parse("Enum").unwrap();
636 let attr = Attribute::try_from(&node)?;
637 assert!(matches!(attr, Attribute::Enum));
638 assert!(attr.is_enum());
639 Ok(())
640 }
641
642 #[test]
643 fn test_error() -> Result<()> {
644 let (_, node) = weedle::attribute::ExtendedAttribute::parse("Error").unwrap();
645 let attr = Attribute::try_from(&node)?;
646 assert!(matches!(attr, Attribute::Error));
647 assert!(attr.is_error());
648 Ok(())
649 }
650
651 #[test]
652 fn test_name() -> Result<()> {
653 let (_, node) = weedle::attribute::ExtendedAttribute::parse("Name=Value").unwrap();
654 let attr = Attribute::try_from(&node)?;
655 assert!(matches!(attr, Attribute::Name(nm) if nm == "Value"));
656
657 let (_, node) = weedle::attribute::ExtendedAttribute::parse("Name").unwrap();
658 let err = Attribute::try_from(&node).unwrap_err();
659 assert_eq!(
660 err.to_string(),
661 "ExtendedAttributeNoArgs not supported: \"Name\""
662 );
663
664 Ok(())
665 }
666
667 #[test]
668 fn test_selftype() -> Result<()> {
669 let (_, node) = weedle::attribute::ExtendedAttribute::parse("Self=ByArc").unwrap();
670 let attr = Attribute::try_from(&node)?;
671 assert!(matches!(attr, Attribute::SelfType(SelfType::ByArc)));
672 let (_, node) = weedle::attribute::ExtendedAttribute::parse("Self=ByMistake").unwrap();
673 let err = Attribute::try_from(&node).unwrap_err();
674 assert_eq!(err.to_string(), "Unsupported Self Type: \"ByMistake\"");
675 Ok(())
676 }
677
678 #[test]
679 fn test_trait() -> Result<()> {
680 let (_, node) = weedle::attribute::ExtendedAttribute::parse("Trait").unwrap();
681 let attr = Attribute::try_from(&node)?;
682 assert!(matches!(attr, Attribute::Trait));
683 Ok(())
684 }
685
686 #[test]
687 fn test_throws() -> Result<()> {
688 let (_, node) = weedle::attribute::ExtendedAttribute::parse("Throws=Name").unwrap();
689 let attr = Attribute::try_from(&node)?;
690 assert!(matches!(attr, Attribute::Throws(nm) if nm == "Name"));
691
692 let (_, node) = weedle::attribute::ExtendedAttribute::parse("Throws").unwrap();
693 let err = Attribute::try_from(&node).unwrap_err();
694 assert_eq!(
695 err.to_string(),
696 "ExtendedAttributeNoArgs not supported: \"Throws\""
697 );
698
699 Ok(())
700 }
701
702 #[test]
703 fn test_unsupported() {
704 let (_, node) =
705 weedle::attribute::ExtendedAttribute::parse("UnsupportedAttribute").unwrap();
706 let err = Attribute::try_from(&node).unwrap_err();
707 assert_eq!(
708 err.to_string(),
709 "ExtendedAttributeNoArgs not supported: \"UnsupportedAttribute\""
710 );
711
712 let (_, node) =
713 weedle::attribute::ExtendedAttribute::parse("Unsupported=Attribute").unwrap();
714 let err = Attribute::try_from(&node).unwrap_err();
715 assert_eq!(
716 err.to_string(),
717 "Attribute identity Identifier not supported: \"Unsupported\""
718 );
719 }
720
721 #[test]
722 fn test_other_attributes_not_supported_for_enums() {
723 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Error, ByRef]").unwrap();
724 let err = EnumAttributes::try_from(&node).unwrap_err();
725 assert_eq!(err.to_string(), "ByRef not supported for enums");
726 }
727
728 #[test]
729 fn test_function_attributes() {
730 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Throws=Error]").unwrap();
731 let attrs = FunctionAttributes::try_from(&node).unwrap();
732 assert!(matches!(attrs.get_throws_err(), Some("Error")));
733 assert!(!attrs.is_async());
734
735 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap();
736 let attrs = FunctionAttributes::try_from(&node).unwrap();
737 assert!(attrs.get_throws_err().is_none());
738 assert!(!attrs.is_async());
739
740 let (_, node) =
741 weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, Async]").unwrap();
742 let attrs = FunctionAttributes::try_from(&node).unwrap();
743 assert!(matches!(attrs.get_throws_err(), Some("Error")));
744 assert!(attrs.is_async());
745 }
746
747 #[test]
748 fn test_other_attributes_not_supported_for_functions() {
749 let (_, node) =
750 weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, ByRef]").unwrap();
751 let err = FunctionAttributes::try_from(&node).unwrap_err();
752 assert_eq!(err.to_string(), "ByRef not supported for functions");
753
754 let (_, node) =
755 weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, Self=ByArc]").unwrap();
756 let err = FunctionAttributes::try_from(&node).unwrap_err();
757 assert_eq!(
758 err.to_string(),
759 "SelfType(ByArc) not supported for functions"
760 );
761 }
762
763 #[test]
764 fn test_method_attributes() {
765 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Throws=Error]").unwrap();
766 let attrs = MethodAttributes::try_from(&node).unwrap();
767 assert!(!attrs.get_self_by_arc());
768 assert!(matches!(attrs.get_throws_err(), Some("Error")));
769 assert!(!attrs.is_async());
770
771 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap();
772 let attrs = MethodAttributes::try_from(&node).unwrap();
773 assert!(!attrs.get_self_by_arc());
774 assert!(attrs.get_throws_err().is_none());
775 assert!(!attrs.is_async());
776
777 let (_, node) =
778 weedle::attribute::ExtendedAttributeList::parse("[Self=ByArc, Throws=Error]").unwrap();
779 let attrs = MethodAttributes::try_from(&node).unwrap();
780 assert!(attrs.get_self_by_arc());
781 assert!(attrs.get_throws_err().is_some());
782 assert!(!attrs.is_async());
783
784 let (_, node) =
785 weedle::attribute::ExtendedAttributeList::parse("[Self=ByArc, Throws=Error, Async]")
786 .unwrap();
787 let attrs = MethodAttributes::try_from(&node).unwrap();
788 assert!(attrs.get_self_by_arc());
789 assert!(attrs.get_throws_err().is_some());
790 assert!(attrs.is_async());
791
792 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Self=ByArc]").unwrap();
793 let attrs = MethodAttributes::try_from(&node).unwrap();
794 assert!(attrs.get_self_by_arc());
795 assert!(attrs.get_throws_err().is_none());
796 assert!(!attrs.is_async());
797 }
798
799 #[test]
800 fn test_constructor_attributes() {
801 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Throws=Error]").unwrap();
802 let attrs = ConstructorAttributes::try_from(&node).unwrap();
803 assert!(matches!(attrs.get_throws_err(), Some("Error")));
804 assert!(attrs.get_name().is_none());
805
806 let (_, node) =
807 weedle::attribute::ExtendedAttributeList::parse("[Name=MyFactory]").unwrap();
808 let attrs = ConstructorAttributes::try_from(&node).unwrap();
809 assert!(attrs.get_throws_err().is_none());
810 assert!(matches!(attrs.get_name(), Some("MyFactory")));
811
812 let (_, node) =
813 weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, Name=MyFactory]")
814 .unwrap();
815 let attrs = ConstructorAttributes::try_from(&node).unwrap();
816 assert!(matches!(attrs.get_throws_err(), Some("Error")));
817 assert!(matches!(attrs.get_name(), Some("MyFactory")));
818 assert!(!attrs.is_async());
819
820 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Async]").unwrap();
821 let attrs = ConstructorAttributes::try_from(&node).unwrap();
822 assert!(attrs.is_async());
823 }
824
825 #[test]
826 fn test_other_attributes_not_supported_for_constructors() {
827 let (_, node) =
828 weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, ByRef]").unwrap();
829 let err = ConstructorAttributes::try_from(&node).unwrap_err();
830 assert_eq!(err.to_string(), "ByRef not supported for constructors");
831
832 let (_, node) =
833 weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, Self=ByArc]").unwrap();
834 let err = ConstructorAttributes::try_from(&node).unwrap_err();
835 assert_eq!(
836 err.to_string(),
837 "SelfType(ByArc) not supported for constructors"
838 );
839 }
840
841 #[test]
842 fn test_byref_attribute() {
843 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[ByRef]").unwrap();
844 let attrs = ArgumentAttributes::try_from(&node).unwrap();
845 assert!(attrs.by_ref());
846
847 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap();
848 let attrs = ArgumentAttributes::try_from(&node).unwrap();
849 assert!(!attrs.by_ref());
850 }
851
852 #[test]
853 fn test_other_attributes_not_supported_for_arguments() {
854 let (_, node) =
855 weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, ByRef]").unwrap();
856 let err = ArgumentAttributes::try_from(&node).unwrap_err();
857 assert_eq!(
858 err.to_string(),
859 "Throws(\"Error\") not supported for arguments"
860 );
861 }
862
863 #[test]
864 fn test_trait_attribute() {
865 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait]").unwrap();
866 let attrs = InterfaceAttributes::try_from(&node).unwrap();
867 assert_eq!(attrs.object_impl().unwrap(), ObjectImpl::Trait);
868
869 let (_, node) =
870 weedle::attribute::ExtendedAttributeList::parse("[Trait, WithForeign]").unwrap();
871 let attrs = InterfaceAttributes::try_from(&node).unwrap();
872 assert_eq!(attrs.object_impl().unwrap(), ObjectImpl::CallbackTrait);
873
874 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap();
875 let attrs = InterfaceAttributes::try_from(&node).unwrap();
876 assert_eq!(attrs.object_impl().unwrap(), ObjectImpl::Struct);
877
878 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[WithForeign]").unwrap();
879 let attrs = InterfaceAttributes::try_from(&node).unwrap();
880 assert!(attrs.object_impl().is_err())
881 }
882
883 #[test]
884 fn test_dictionary_attributes() {
885 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Remote]").unwrap();
886 let attrs = DictionaryAttributes::try_from(&node).unwrap();
887 assert!(attrs.contains_remote());
888
889 let (_, node) =
890 weedle::attribute::ExtendedAttributeList::parse("[Traits=(Debug)]").unwrap();
891 DictionaryAttributes::try_from(&node).unwrap();
892
893 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait]").unwrap();
894 let err = DictionaryAttributes::try_from(&node).unwrap_err();
895 assert_eq!(err.to_string(), "Trait not supported for dictionaries");
896 }
897
898 #[test]
899 fn test_enum_attribute_on_interface() {
900 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Enum]").unwrap();
901 let attrs = InterfaceAttributes::try_from(&node).unwrap();
902 assert!(attrs.contains_enum_attr());
903
904 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap();
905 let attrs = InterfaceAttributes::try_from(&node).unwrap();
906 assert!(!attrs.contains_enum_attr());
907
908 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait]").unwrap();
909 let attrs = InterfaceAttributes::try_from(&node).unwrap();
910 assert!(!attrs.contains_enum_attr());
911
912 let (_, node) =
913 weedle::attribute::ExtendedAttributeList::parse("[Traits=(Debug), Enum]").unwrap();
914 InterfaceAttributes::try_from(&node).unwrap();
915
916 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait, Enum]").unwrap();
917 let err = InterfaceAttributes::try_from(&node).unwrap_err();
918 assert_eq!(
919 err.to_string(),
920 "conflicting attributes on interface definition"
921 );
922 }
923
924 #[test]
926 fn test_enum_attributes() {
927 let (_, node) =
928 weedle::attribute::ExtendedAttributeList::parse("[Error, NonExhaustive, Remote]")
929 .unwrap();
930 let attrs = EnumAttributes::try_from(&node).unwrap();
931 assert!(attrs.contains_error_attr());
932 assert!(attrs.contains_non_exhaustive_attr());
933 assert!(attrs.contains_remote());
934
935 let (_, node) =
936 weedle::attribute::ExtendedAttributeList::parse("[Traits=(Display)]").unwrap();
937 EnumAttributes::try_from(&node).unwrap();
938
939 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait]").unwrap();
940 let err = EnumAttributes::try_from(&node).unwrap_err();
941 assert_eq!(err.to_string(), "Trait not supported for enums");
942 }
943
944 #[test]
946 fn test_enum_attributes_from_interface() {
947 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Enum]").unwrap();
948 assert!(EnumAttributes::try_from(&node).is_ok());
949
950 let (_, node) =
951 weedle::attribute::ExtendedAttributeList::parse("[Enum, Error, NonExhaustive, Remote]")
952 .unwrap();
953 let attrs = EnumAttributes::try_from(&node).unwrap();
954 assert!(attrs.contains_error_attr());
955 assert!(attrs.contains_non_exhaustive_attr());
956 assert!(attrs.contains_remote());
957
958 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Enum, Trait]").unwrap();
959 let err = EnumAttributes::try_from(&node).unwrap_err();
960 assert_eq!(err.to_string(), "Trait not supported for enums");
961 }
962
963 #[test]
964 fn test_interface_attributes() {
965 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Remote]").unwrap();
966 let attrs = InterfaceAttributes::try_from(&node).unwrap();
967 assert!(attrs.contains_remote());
968
969 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait, ByRef]").unwrap();
970 let err = InterfaceAttributes::try_from(&node).unwrap_err();
971 assert_eq!(
972 err.to_string(),
973 "ByRef not supported for interface definition"
974 );
975 }
976
977 #[test]
978 fn test_typedef_attribute() {
979 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Custom]").unwrap();
980 let attrs = TypedefAttributes::try_from(&node).unwrap();
981 assert!(attrs.is_custom());
982 assert!(attrs.get_crate_name().is_none());
983
984 let (_, node) =
985 weedle::attribute::ExtendedAttributeList::parse("[Custom=\"crate_name\"]").unwrap();
986 let attrs = TypedefAttributes::try_from(&node).unwrap();
987 assert!(attrs.is_custom());
988 assert_eq!(attrs.get_crate_name().unwrap(), "crate_name");
989
990 let (_, node) =
991 weedle::attribute::ExtendedAttributeList::parse("[External=crate_name]").unwrap();
992 let attrs = TypedefAttributes::try_from(&node).unwrap();
993 assert!(!attrs.is_custom());
994 assert_eq!(attrs.get_crate_name().unwrap(), "crate_name");
995 }
996
997 #[test]
998 fn test_typedef_attributes_malformed() {
999 let (_, node) =
1000 weedle::attribute::ExtendedAttributeList::parse("[External=foo, Custom]").unwrap();
1001 let err = TypedefAttributes::try_from(&node).unwrap_err();
1002 assert_eq!(err.to_string(), "Can't be [Custom] and [External]");
1003
1004 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[External]").unwrap();
1005 let err = TypedefAttributes::try_from(&node).unwrap_err();
1006 assert_eq!(
1007 err.to_string(),
1008 "ExtendedAttributeNoArgs not supported: \"External\""
1009 );
1010 }
1011
1012 #[test]
1013 fn test_other_attributes_not_supported_for_typedef() {
1014 let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[ByRef]").unwrap();
1015 let err = TypedefAttributes::try_from(&node).unwrap_err();
1016 assert_eq!(err.to_string(), "ByRef not supported for typedefs");
1017 }
1018}