codama_attributes/
codama_program_macro.rs1use crate::utils::SetOnce;
2use codama_nodes::CamelCaseString;
3use codama_syn_helpers::{extensions::*, Meta};
4use proc_macro2::TokenStream;
5
6#[derive(Debug, PartialEq)]
15pub struct CodamaProgramMacro {
16 pub name: Option<CamelCaseString>,
17 pub address: Option<String>,
18}
19
20impl CodamaProgramMacro {
21 pub fn parse(tokens: TokenStream) -> syn::Result<Self> {
23 let meta: Meta = syn::parse_quote! { codama_program(#tokens) };
25 let pl = meta.as_path_list()?;
26
27 let mut name = SetOnce::<CamelCaseString>::new("name");
28 let mut address = SetOnce::<String>::new("address");
29
30 pl.each(|ref meta| match meta.path_str().as_str() {
31 "name" => name.set(meta.as_value()?.as_expr()?.as_string()?.into(), meta),
32 "address" => address.set(meta.as_value()?.as_expr()?.as_string()?, meta),
33 _ => Err(meta.error("unrecognized attribute")),
34 })?;
35
36 let name = name.option();
37 let address = address.option();
38 if name.is_none() && address.is_none() {
39 return Err(meta.error("expected at least one of `name` or `address`"));
40 }
41
42 Ok(Self { name, address })
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49 use quote::quote;
50
51 #[test]
52 fn name_only() {
53 let program = CodamaProgramMacro::parse(quote! { name = "associatedToken" }).unwrap();
54 assert_eq!(
55 program,
56 CodamaProgramMacro {
57 name: Some(CamelCaseString::from("associatedToken")),
58 address: None,
59 }
60 );
61 }
62
63 #[test]
64 fn address_only() {
65 let program = CodamaProgramMacro::parse(
66 quote! { address = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" },
67 )
68 .unwrap();
69 assert_eq!(
70 program,
71 CodamaProgramMacro {
72 name: None,
73 address: Some("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL".to_string()),
74 }
75 );
76 }
77
78 #[test]
79 fn name_and_address() {
80 let program = CodamaProgramMacro::parse(
81 quote! { name = "associatedToken", address = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" },
82 )
83 .unwrap();
84 assert_eq!(
85 program,
86 CodamaProgramMacro {
87 name: Some(CamelCaseString::from("associatedToken")),
88 address: Some("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL".to_string()),
89 }
90 );
91 }
92
93 #[test]
94 fn empty() {
95 let error = CodamaProgramMacro::parse(quote! {}).unwrap_err();
96 assert_eq!(
97 error.to_string(),
98 "expected at least one of `name` or `address`"
99 );
100 }
101
102 #[test]
103 fn unrecognized_attribute() {
104 let error =
105 CodamaProgramMacro::parse(quote! { name = "foo", version = "1.0.0" }).unwrap_err();
106 assert_eq!(error.to_string(), "unrecognized attribute");
107 }
108}