#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InjectableAttrs {
pub scope: Scope,
pub has_post_construct: bool,
pub has_pre_destruct: bool,
}
impl Default for InjectableAttrs {
fn default() -> Self {
Self {
scope: Scope::Singleton,
has_post_construct: false,
has_pre_destruct: false,
}
}
}
pub fn parse_attrs(attrs: &[syn::Attribute]) -> syn::Result<InjectableAttrs> {
let mut result = InjectableAttrs::default();
for attr in attrs {
if attr.path().is_ident("injectable") {
let args: syn::punctuated::Punctuated<InjectableArg, syn::Token![,]> =
attr.parse_args_with(syn::punctuated::Punctuated::parse_terminated)?;
for arg in args {
match arg {
InjectableArg::Scope(s) => {
result.scope = match s.as_str() {
"singleton" => Scope::Singleton,
"transient" => Scope::Transient,
"request" => Scope::Request,
other => Scope::Custom(other.to_string()),
};
}
InjectableArg::HasPostConstruct => {
result.has_post_construct = true;
}
InjectableArg::HasPreDestruct => {
result.has_pre_destruct = true;
}
}
}
}
}
Ok(result)
}
enum InjectableArg {
Scope(String),
HasPostConstruct,
HasPreDestruct,
}
impl syn::parse::Parse for InjectableArg {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(syn::Ident) {
let ident: syn::Ident = input.parse()?;
if ident == "scope" {
input.parse::<syn::Token![=]>()?;
let lit: syn::LitStr = input.parse()?;
Ok(InjectableArg::Scope(lit.value()))
} else if ident == "has_post_construct" {
Ok(InjectableArg::HasPostConstruct)
} else if ident == "has_pre_destruct" {
Ok(InjectableArg::HasPreDestruct)
} else {
Err(syn::Error::new(
ident.span(),
format!("unknown injectable attribute: `{ident}`"),
))
}
} else {
Err(lookahead.error())
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Scope {
Singleton,
Transient,
Request,
Custom(String),
}
impl std::fmt::Display for Scope {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Scope::Singleton => write!(f, "singleton"),
Scope::Transient => write!(f, "transient"),
Scope::Request => write!(f, "request"),
Scope::Custom(name) => write!(f, "{name}"),
}
}
}
impl Scope {
pub fn as_str(&self) -> &'static str {
match self {
Scope::Singleton => "singleton",
Scope::Transient => "transient",
Scope::Request => "request",
Scope::Custom(_) => "custom",
}
}
}