use codama_nodes::{BytesEncoding, Docs, InstructionOptionalAccountStrategy, IsAccountSigner};
use codama_syn_helpers::{extensions::*, Meta};
use syn::Expr;
pub trait FromMeta
where
Self: Sized,
{
fn from_meta(meta: &Meta) -> syn::Result<Self>;
}
impl FromMeta for bool {
fn from_meta(meta: &Meta) -> syn::Result<Self> {
match meta {
Meta::Expr(Expr::Path(_)) => Ok(true),
_ => meta.as_expr_or_value_expr()?.as_bool(),
}
}
}
impl FromMeta for IsAccountSigner {
fn from_meta(meta: &Meta) -> syn::Result<Self> {
if let Ok(value) = bool::from_meta(meta) {
return Ok(value.into());
}
let expr = meta.as_expr_or_value_expr()?;
match expr.as_string() {
Ok(value) if value == "either" => Ok(Self::Either),
_ => Err(expr.error("expected boolean or `\"either\"`")),
}
}
}
impl FromMeta for BytesEncoding {
fn from_meta(meta: &Meta) -> syn::Result<Self> {
let expr = meta.as_expr_or_value_expr()?;
if let Ok(value) = expr.as_string() {
if let Ok(encoding) = Self::try_from(value) {
return Ok(encoding);
}
}
Err(expr.error("expected one of: \"base16\", \"base58\", \"base64\", \"utf8\""))
}
}
impl FromMeta for InstructionOptionalAccountStrategy {
fn from_meta(meta: &Meta) -> syn::Result<Self> {
let expr = meta.as_expr_or_value_expr()?;
let path = expr.as_path()?;
match path.to_string().as_str() {
"omitted" => Ok(Self::Omitted),
"program_id" => Ok(Self::ProgramId),
_ => Err(path.error("expected `omitted` or `program_id`")),
}
}
}
impl FromMeta for Docs {
fn from_meta(meta: &Meta) -> syn::Result<Self> {
match meta {
Meta::PathList(pl) if pl.eq_token.is_some() => {
let strings: Vec<String> = pl
.as_meta_list()
.parse_comma_args::<syn::LitStr>()?
.into_iter()
.map(|lit| lit.value())
.collect();
Ok(strings.into())
}
Meta::PathValue(pv) => pv.value.as_expr()?.as_string().map(|s| vec![s].into()),
_ => Err(meta.error("expected a string or array of strings")),
}
}
}