attr_parser_fn/meta/
conflicts.rs1use impl_variadics::impl_variadics;
2use proc_macro2::Span;
3use syn::{meta::ParseNestedMeta, Error, Result};
4
5use super::ParseMeta;
6
7pub fn conflicts<T>(group: T) -> Conflicts<T>
8where
9 T: ConflictGroup,
10{
11 Conflicts {
12 parser: group,
13 selected: None,
14 }
15}
16
17pub struct Conflicts<T>
18where
19 T: ConflictGroup,
20{
21 parser: T,
22 selected: Option<(String, u8)>,
23}
24
25pub trait ConflictGroup: Sized {
26 type Output;
27
28 fn parse_meta_conflict_alternative_arm(&self, f: &mut dyn std::fmt::Write) -> std::fmt::Result;
29 fn parse(&mut self, nested: &ParseNestedMeta) -> Result<Option<u8>>;
30 fn finish(self, index: u8) -> Result<<Self as ConflictGroup>::Output>;
31}
32
33impl_variadics! {
34 1..21 "T*" => {
35 impl<Out, #(#T0,)*> ConflictGroup for (#(#T0,)*)
36 where
37 #(#T0: ParseMeta<Output = Out>,)*
38 {
39 type Output = Out;
40
41 fn parse_meta_conflict_alternative_arm(&self, f: &mut dyn std::fmt::Write) -> std::fmt::Result {
42 self.conflict_alternative_arm(f)
43 }
44
45 fn parse(&mut self, nested: &ParseNestedMeta) -> Result<Option<u8>> {
46 #(if self.#index.parse(nested)? {
47 Ok(Some(#index))
48 } else)* {
49 Ok(None)
50 }
51 }
52
53 fn finish(self, index: u8) -> Result<<Self as ConflictGroup>::Output> {
54 match index {
55 #(#index => self.#index.finish(),)*
56 _ => unreachable!("invalid index")
57 }
58 }
59 }
60 }
61}
62
63impl<T> ParseMeta for Conflicts<T>
64where
65 T: ConflictGroup,
66{
67 type Output = T::Output;
68
69 fn conflict_alternative_arm(&self, f: &mut dyn std::fmt::Write) -> std::fmt::Result {
70 write!(f, "(conflict group: ")?;
71 self.parser.parse_meta_conflict_alternative_arm(f)?;
72 write!(f, ")")
73 }
74
75 fn parse(&mut self, nested: &ParseNestedMeta) -> Result<bool> {
76 match self.parser.parse(nested)? {
77 Some(index) => {
78 let new_name = nested.path.require_ident()?.to_string();
79 match &self.selected {
80 Some((name, _)) => Err(Error::new_spanned(
81 &nested.path,
82 format!("attribute `{new_name}` is conflicts with `{name}`"),
83 )),
84
85 None => {
86 self.selected = Some((new_name, index));
87 Ok(true)
88 }
89 }
90 }
91
92 None => Ok(false),
93 }
94 }
95
96 fn finish(self) -> Result<Self::Output> {
97 match self.selected {
98 Some((_, index)) => self.parser.finish(index),
99 None => Err(Error::new(Span::call_site(), {
100 let mut msg = "one of following attributes must be provided: ".to_string();
101 self.parser
102 .parse_meta_conflict_alternative_arm(&mut msg)
103 .unwrap();
104 msg
105 })),
106 }
107 }
108
109 fn ok_to_finish(&self) -> bool {
110 self.selected.is_some()
111 }
112}