singleton

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:

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:

NameKindRequired
idArgumentNo
clone_if_necessaryFlagNo
never_cloneFlagNo
allowArgumentNo

§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 {
            // [...]
        }
    }
}