Attribute Macro singleton
#[singleton]Expand description
Define a singleton constructor.
Singleton constructors are invoked once (when the application starts up) to create a new instance of their output type. The created instance is then shared across all requests for the lifetime of the application.
Check out #[request_scoped] and #[transient]
if you need to define constructors with different lifecycles.
§Example
use pavex::methods;
pub struct DatabasePool {
// [...]
}
#[methods]
impl DatabasePool {
#[singleton]
pub fn new() -> Self {
Self {
// [...]
}
}
}DatabasePool::new will be called once at application startup, and the resulting
instance will be shared across all requests.
§Guide
Check out the “Dependency injection” section of Pavex’s guide for a thorough introduction to dependency injection in Pavex applications.
§Registration
You can register a singleton constructor with your application in two ways:
- Use
Blueprint::constructorto register a single constructor - Use
Blueprint::importto import multiple constructors in bulk
The #[singleton] macro generates a constant that you can use to refer to the
constructor when invoking Blueprint::constructor.
§Arguments
The sections below provide an exhaustive list of all the arguments and flags supported by the singleton macro:
| Name | Kind | Required |
|---|---|---|
id | Argument | No |
clone_if_necessary | Flag | No |
never_clone | Flag | No |
allow | Argument | No |
§id
By default, Pavex generates a constant named after your type and method (converted to UPPER_SNAKE_CASE) that you use when registering the constructor.
The id argument allows you to customize the name of the generated constant.
§Example
Using the default generated identifier:
use pavex::{methods, Blueprint};
pub struct CacheManager {
// [...]
}
#[methods]
impl CacheManager {
#[singleton]
pub fn new() -> Self {
Self {
// [...]
}
}
}
let mut bp = Blueprint::new();
// The generated constant is named `CACHE_MANAGER_NEW`
bp.constructor(CACHE_MANAGER_NEW);Using a custom identifier:
use pavex::{methods, Blueprint};
pub struct CacheManager {
// [...]
}
#[methods]
impl CacheManager {
#[singleton(id = "CACHE_CONSTRUCTOR")]
// 👆 Custom identifier
pub fn new() -> Self {
Self {
// [...]
}
}
}
let mut bp = Blueprint::new();
// Use the custom identifier when registering
bp.constructor(CACHE_CONSTRUCTOR);§clone_if_necessary
By default, Pavex will not clone the output of singleton constructors. The clone_if_necessary
flag allows Pavex to invoke .clone() on the output if it helps satisfy Rust’s borrow checker.
The constructed type must implement the Clone trait.
This flag is mutually exclusive with never_clone.
§Example
use pavex::methods;
use std::collections::HashMap;
#[derive(Clone)]
pub struct GlobalConfig {
settings: HashMap<String, String>,
}
#[methods]
impl GlobalConfig {
#[singleton(clone_if_necessary)]
// 👆 Allow cloning when needed
pub fn new() -> Self {
Self {
settings: HashMap::new(),
}
}
}§never_clone
The never_clone flag explicitly prevents Pavex from cloning the output of this constructor.
This is the default behavior for singleton constructors, so this flag is typically used
for clarity and explicitness.
This flag is mutually exclusive with clone_if_necessary.
§Example
use pavex::methods;
pub struct LogSink {
// Contains non-cloneable resources
handle: std::fs::File,
}
#[methods]
impl LogSink {
#[singleton(never_clone)]
// 👆 Explicitly prevent cloning (default behavior)
pub fn new() -> std::io::Result<Self> {
Ok(Self {
handle: std::fs::File::create("global.log")?,
})
}
}Pavex will report an error during the code-generation phase if cloning is required but forbidden.
§allow
The allow argument can be used to suppress specific warnings.
Currently, only one value is supported:
unused: Suppress warnings if this constructor is registered but never used
§Example
use pavex::methods;
pub struct MetricsCollector {
// [...]
}
#[methods]
impl MetricsCollector {
#[singleton(allow(unused))]
// 👆 Don't warn if unused
pub fn new() -> Self {
Self {
// [...]
}
}
}