1use std::str::FromStr;
4use syn::spanned::Spanned as _;
5use syn::{meta, Attribute, Error, LitStr, Path, Result};
6
7#[derive(Debug, Default)]
9pub(crate) enum AssignOnce<T> {
10 Set(T),
11 #[default]
12 Unset,
13}
14
15impl<T> AssignOnce<T> {
16 pub(crate) fn set<E, F>(&mut self, value: T, err: F) -> std::result::Result<(), E>
18 where
19 F: FnOnce() -> E,
20 {
21 match self {
22 AssignOnce::Set(_) => Err(err()),
23 AssignOnce::Unset => {
24 *self = AssignOnce::Set(value);
25 Ok(())
26 }
27 }
28 }
29
30 pub(crate) fn default_to(self, default: T) -> T {
32 match self {
33 AssignOnce::Set(value) => value,
34 AssignOnce::Unset => default,
35 }
36 }
37
38 pub(crate) fn into_option(self) -> Option<T> {
40 match self {
41 AssignOnce::Set(value) => Some(value),
42 AssignOnce::Unset => None,
43 }
44 }
45
46 pub(crate) fn unwrap_or_err<E, F>(self, err: F) -> std::result::Result<T, E>
48 where
49 F: FnOnce() -> E,
50 {
51 match self {
52 AssignOnce::Set(value) => Ok(value),
53 AssignOnce::Unset => Err(err()),
54 }
55 }
56}
57
58pub(crate) fn assign_str_value(
60 to: &mut AssignOnce<String>,
61 attr: &Attribute,
62 key: &str,
63 meta: &meta::ParseNestedMeta<'_>,
64) -> Result<()> {
65 let value = meta.value()?;
66 let value: LitStr = value.parse()?;
67 to.set(value.value(), || {
68 Error::new(
69 attr.span(),
70 format!("parameter `{key}` was already specified."),
71 )
72 })
73}
74
75pub(crate) fn parse_str_value<T>(
77 to: &mut AssignOnce<T>,
78 attr: &Attribute,
79 key: &str,
80 meta: &meta::ParseNestedMeta<'_>,
81) -> Result<()>
82where
83 T: FromStr<Err = String>,
84{
85 let value = meta.value()?;
86 let value: LitStr = value.parse::<LitStr>()?;
87 let value = value
88 .value()
89 .parse()
90 .map_err(|err| Error::new(attr.span(), err))?;
91 to.set(value, || {
92 Error::new(
93 attr.span(),
94 format!("parameter `{key}` was already specified."),
95 )
96 })
97}
98
99pub(crate) fn assign_path(
101 to: &mut AssignOnce<Path>,
102 attr: &Attribute,
103 key: &str,
104 meta: &meta::ParseNestedMeta<'_>,
105) -> Result<()> {
106 meta.parse_nested_meta(|meta| {
107 to.set(meta.path, || {
108 Error::new(
109 attr.span(),
110 format!("attribute `{key}` was already specified."),
111 )
112 })?;
113 Ok(())
114 })
115}