use syn::{Lit, LitStr};
fn parse_lit<T, F>(
meta: &syn::meta::ParseNestedMeta,
key: &str,
extractor: F,
) -> Result<T, syn::Error>
where
F: FnOnce(Lit) -> Option<T>,
{
let literal = meta.value()?.parse::<Lit>()?;
let span = literal.span();
extractor(literal).ok_or_else(|| {
let type_name = std::any::type_name::<T>()
.rsplit("::")
.next()
.unwrap_or("literal")
.to_lowercase();
let display_type = match type_name.as_str() {
"litstr" => "string",
other => other,
};
syn::Error::new(span, format!("{key} must be a {display_type}"))
})
}
pub(crate) fn lit_str(meta: &syn::meta::ParseNestedMeta, key: &str) -> Result<LitStr, syn::Error> {
parse_lit(meta, key, |lit| match lit {
Lit::Str(s) => Some(s),
_ => None,
})
}
pub(crate) fn lit_char(meta: &syn::meta::ParseNestedMeta, key: &str) -> Result<char, syn::Error> {
parse_lit(meta, key, |lit| match lit {
Lit::Char(c) => Some(c.value()),
_ => None,
})
}
pub(crate) fn lit_bool(meta: &syn::meta::ParseNestedMeta, key: &str) -> Result<bool, syn::Error> {
parse_lit(meta, key, |lit| match lit {
Lit::Bool(b) => Some(b.value),
_ => None,
})
}
pub(crate) fn lit_crate_path(meta: &syn::meta::ParseNestedMeta) -> Result<syn::Path, syn::Error> {
let s = lit_str(meta, "crate")?;
syn::parse_str(&s.value()).map_err(|e| syn::Error::new(s.span(), e))
}
#[cfg(any(test, doctest))]
#[doc(hidden)]
pub fn __doc_lit_str(meta: &syn::meta::ParseNestedMeta, key: &str) -> Result<LitStr, syn::Error> {
lit_str(meta, key)
}