use crate::utils::SetOnce;
use codama_nodes::CamelCaseString;
use codama_syn_helpers::{extensions::*, Meta};
use proc_macro2::TokenStream;
#[derive(Debug, PartialEq)]
pub struct CodamaProgramMacro {
pub name: Option<CamelCaseString>,
pub address: Option<String>,
}
impl CodamaProgramMacro {
pub fn parse(tokens: TokenStream) -> syn::Result<Self> {
let meta: Meta = syn::parse_quote! { codama_program(#tokens) };
let pl = meta.as_path_list()?;
let mut name = SetOnce::<CamelCaseString>::new("name");
let mut address = SetOnce::<String>::new("address");
pl.each(|ref meta| match meta.path_str().as_str() {
"name" => name.set(meta.as_value()?.as_expr()?.as_string()?.into(), meta),
"address" => address.set(meta.as_value()?.as_expr()?.as_string()?, meta),
_ => Err(meta.error("unrecognized attribute")),
})?;
let name = name.option();
let address = address.option();
if name.is_none() && address.is_none() {
return Err(meta.error("expected at least one of `name` or `address`"));
}
Ok(Self { name, address })
}
}
#[cfg(test)]
mod tests {
use super::*;
use quote::quote;
#[test]
fn name_only() {
let program = CodamaProgramMacro::parse(quote! { name = "associatedToken" }).unwrap();
assert_eq!(
program,
CodamaProgramMacro {
name: Some(CamelCaseString::from("associatedToken")),
address: None,
}
);
}
#[test]
fn address_only() {
let program = CodamaProgramMacro::parse(
quote! { address = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" },
)
.unwrap();
assert_eq!(
program,
CodamaProgramMacro {
name: None,
address: Some("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL".to_string()),
}
);
}
#[test]
fn name_and_address() {
let program = CodamaProgramMacro::parse(
quote! { name = "associatedToken", address = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" },
)
.unwrap();
assert_eq!(
program,
CodamaProgramMacro {
name: Some(CamelCaseString::from("associatedToken")),
address: Some("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL".to_string()),
}
);
}
#[test]
fn empty() {
let error = CodamaProgramMacro::parse(quote! {}).unwrap_err();
assert_eq!(
error.to_string(),
"expected at least one of `name` or `address`"
);
}
#[test]
fn unrecognized_attribute() {
let error =
CodamaProgramMacro::parse(quote! { name = "foo", version = "1.0.0" }).unwrap_err();
assert_eq!(error.to_string(), "unrecognized attribute");
}
}