use syn::{
Error, Expr, ExprLit, Lit, MetaNameValue, Result,
parse::{Parse, ParseStream},
spanned::Spanned,
};
const PUBLIC_VISIBILITY: &str = "pub";
const PRIVATE_VISIBILITY: &str = "private";
use crate::constructor::constructor_visibility::ConstructorVisibility;
pub enum ConstructorArg {
Name(String),
Visibility(ConstructorVisibility),
}
impl ConstructorArg {
pub fn nv_to_arg(nv: &MetaNameValue) -> Result<Self> {
match nv
.path
.get_ident()
.expect("Wrong name. Expected Identifier")
.to_string()
.as_str()
{
"name" => Ok(ConstructorArg::Name(ConstructorArg::string_from_nv_value(
&nv.value,
)?)),
"visibility" => Ok(ConstructorArg::Visibility(
ConstructorArg::visibility_from_nv_value(&nv.value)?,
)),
_ => Result::Err(Error::new(nv.span(), "Unknown arg name")),
}
}
pub fn string_from_nv_value(e: &Expr) -> Result<String> {
if let Expr::Path(p) = e {
return Ok(p
.path
.get_ident()
.expect("Error, expected string")
.to_string());
}
return Err(Error::new(e.span(), "Error, expected string"));
}
pub fn visibility_parse_pub_path(e: String, v: &String) -> Result<ConstructorVisibility> {
if v.starts_with("pub(") && v.ends_with(")") {
let path = &v["pub(".len()..v.len() - 1];
return Ok(ConstructorVisibility::PubPath(path.to_string()));
}
Err(Error::new(e.span(), e.as_str()))
}
pub fn visibility_from_nv_value(e: &Expr) -> Result<ConstructorVisibility> {
let _error_unexpected_symbol = format!(
"Error, expected one of: \"{}\", \"{}\", \"{}\"",
PUBLIC_VISIBILITY,
PRIVATE_VISIBILITY,
format!("{}(path)", PUBLIC_VISIBILITY)
);
if let Expr::Lit(ExprLit {
lit: Lit::Str(s), ..
}) = e
{
if &s.value() == PUBLIC_VISIBILITY {
Ok(ConstructorVisibility::Pub)
} else if &s.value() == PRIVATE_VISIBILITY {
Ok(ConstructorVisibility::Private)
} else {
ConstructorArg::visibility_parse_pub_path(_error_unexpected_symbol, &s.value())
}
} else {
Err(Error::new(e.span(), _error_unexpected_symbol.as_str()))
}
}
}
impl Parse for ConstructorArg {
fn parse(input: ParseStream) -> Result<Self> {
let arg = if let Ok(nv) = input.parse::<MetaNameValue>() {
ConstructorArg::nv_to_arg(&nv)?
} else {
return Result::Err(Error::new(
input.span(),
"Could not parse arg. Expected name-value",
));
};
Ok(arg)
}
}