RankedSemaphore

Struct RankedSemaphore 

Source
pub struct RankedSemaphore { /* private fields */ }
Expand description

A priority-aware semaphore for controlling access to shared resources.

RankedSemaphore maintains a count of available permits and allows tasks to acquire permits with different priorities. Higher priority tasks are served before lower priority tasks when permits become available.

The semaphore supports:

  • Priority-based scheduling with configurable queue strategies
  • Multiple permit acquisition
  • Both borrowed and owned permit types
  • Graceful shutdown via the close() method

§Examples

use ranked_semaphore::RankedSemaphore;
use std::sync::Arc;

let sem = Arc::new(RankedSemaphore::new_fifo(2));

// High priority task
let high_permit = sem.acquire_with_priority(10).await.unwrap();

// Low priority task will wait
let low_permit = sem.acquire_with_priority(1).await.unwrap();

Implementations§

Source§

impl RankedSemaphore

Source

pub const MAX_PERMITS: usize = 2_305_843_009_213_693_951usize

Maximum permits (reserve 3 bits for flags, same as tokio)

Source

pub fn new_fifo(permits: usize) -> Self

Creates a new semaphore with FIFO (First In, First Out) queue strategy.

All waiters regardless of priority will be served in the order they arrive. This is the most common queue strategy for fair resource allocation.

§Arguments
  • permits - The initial number of permits available
§Panics

Panics if permits exceeds MAX_PERMITS (usize::MAX >> 3).

§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_fifo(3);
assert_eq!(sem.available_permits(), 3);
Source

pub fn new_lifo(permits: usize) -> Self

Creates a new semaphore with LIFO (Last In, First Out) queue strategy.

All waiters regardless of priority will be served in reverse order of arrival. This can be useful for scenarios where you want to prioritize recently arrived tasks.

§Arguments
  • permits - The initial number of permits available
§Panics

Panics if permits exceeds MAX_PERMITS (usize::MAX >> 3).

§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_lifo(3);
assert_eq!(sem.available_permits(), 3);
Source

pub fn new(permits: usize, default_strategy: QueueStrategy) -> Self

Creates a new semaphore with the specified default queue strategy.

All waiters will use the specified queue strategy regardless of their priority. For more fine-grained control over queue strategies per priority level, use new_with_config().

§Arguments
  • permits - The initial number of permits available
  • default_strategy - The queue strategy to use for all waiters
§Panics

Panics if permits exceeds MAX_PERMITS (usize::MAX >> 3).

§Examples
use ranked_semaphore::{RankedSemaphore, QueueStrategy};

let sem = RankedSemaphore::new(3, QueueStrategy::Fifo);
assert_eq!(sem.available_permits(), 3);
Source

pub fn new_with_config(permits: usize, config: PriorityConfig) -> Self

Creates a new semaphore with custom priority-based configuration.

This allows fine-grained control over queue strategies for different priority levels. Different priorities can use different queue strategies (FIFO or LIFO) based on the configuration rules.

§Arguments
  • permits - The initial number of permits available
  • config - The priority configuration specifying queue strategies
§Panics

Panics if permits exceeds MAX_PERMITS (usize::MAX >> 3).

§Examples
use ranked_semaphore::{RankedSemaphore, PriorityConfig, QueueStrategy};

let config = PriorityConfig::new()
    .default_strategy(QueueStrategy::Fifo)
    .exact(10, QueueStrategy::Lifo); // Priority 10 uses LIFO

let sem = RankedSemaphore::new_with_config(3, config);
assert_eq!(sem.available_permits(), 3);
Source

pub fn available_permits(&self) -> usize

Returns the current number of available permits.

This value represents permits that can be acquired immediately without waiting. Note that this value can change rapidly in concurrent environments.

§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_fifo(3);
assert_eq!(sem.available_permits(), 3);

let _permit = sem.try_acquire().unwrap();
assert_eq!(sem.available_permits(), 2);
Source

pub fn is_closed(&self) -> bool

Returns true if the semaphore has been closed.

A closed semaphore will not issue new permits and all pending acquire operations will return AcquireError::Closed.

§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_fifo(3);
assert!(!sem.is_closed());

sem.close();
assert!(sem.is_closed());
Source

pub fn add_permits(&self, added: usize)

Adds permits to the semaphore and notifies waiting tasks.

If there are tasks waiting for permits, they will be notified in priority order. Any excess permits (beyond what waiting tasks need) are added to the semaphore’s available permit count.

§Arguments
  • added - The number of permits to add
§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_fifo(1);
let _permit = sem.try_acquire().unwrap();
assert_eq!(sem.available_permits(), 0);

sem.add_permits(2);
assert_eq!(sem.available_permits(), 2);
Source

pub fn close(&self)

Closes the semaphore and cancels all pending waiters.

After calling this method:

  • No new permits will be issued
  • All pending acquire operations will return AcquireError::Closed
  • All try_acquire operations will return TryAcquireError::Closed

This operation is irreversible - once closed, a semaphore cannot be reopened.

§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_fifo(3);
sem.close();
 
assert!(sem.is_closed());
assert!(sem.try_acquire().is_err());
Source

pub fn forget_permits(&self, n: usize) -> usize

Permanently removes permits from the semaphore.

This operation reduces the number of available permits without releasing them back to the semaphore. It’s useful for scenarios where the resource pool needs to be dynamically reduced.

§Arguments
  • n - The number of permits to remove
§Returns

The number of permits that were actually removed. This may be less than n if there were insufficient permits available.

§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_fifo(5);
assert_eq!(sem.available_permits(), 5);

let removed = sem.forget_permits(3);
assert_eq!(removed, 3);
assert_eq!(sem.available_permits(), 2);

// Trying to remove more permits than available
let removed = sem.forget_permits(10);
assert_eq!(removed, 2); // Only 2 were available
assert_eq!(sem.available_permits(), 0);
§Warning

Use this method with caution. Removing too many permits can lead to resource starvation if tasks are waiting for permits that will never become available.

Source§

impl RankedSemaphore

Source

pub fn acquire( &self, ) -> impl Future<Output = Result<RankedSemaphorePermit<'_>, AcquireError>>

Acquires a single permit with default priority (0).

This method will wait until a permit becomes available. If the semaphore is closed while waiting, it returns AcquireError::Closed.

§Returns

A future that resolves to either:

  • Ok(RankedSemaphorePermit) - Successfully acquired permit
  • Err(AcquireError) - Semaphore was closed
§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_fifo(1);
let permit = sem.acquire().await.unwrap();
// Permit is automatically released when dropped
Source

pub fn acquire_with_priority( &self, priority: isize, ) -> impl Future<Output = Result<RankedSemaphorePermit<'_>, AcquireError>>

Acquires a single permit with the specified priority.

Higher priority values are served first. Tasks with the same priority are served according to the queue strategy (FIFO or LIFO).

§Arguments
  • priority - The priority level for this acquisition request
§Returns

A future that resolves to either:

  • Ok(RankedSemaphorePermit) - Successfully acquired permit
  • Err(AcquireError) - Semaphore was closed
§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_fifo(1);
let permit = sem.acquire_with_priority(10).await.unwrap();
Source

pub fn acquire_many( &self, n: u32, ) -> impl Future<Output = Result<RankedSemaphorePermit<'_>, AcquireError>>

Acquires multiple permits with default priority (0).

This method will wait until all requested permits become available. The operation is atomic - either all permits are acquired or none are.

§Arguments
  • n - The number of permits to acquire
§Returns

A future that resolves to either:

  • Ok(RankedSemaphorePermit) - Successfully acquired all permits
  • Err(AcquireError) - Semaphore was closed
§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_fifo(5);
let permits = sem.acquire_many(3).await.unwrap();
assert_eq!(permits.num_permits(), 3);
Source

pub fn acquire_many_with_priority( &self, priority: isize, n: u32, ) -> impl Future<Output = Result<RankedSemaphorePermit<'_>, AcquireError>>

Acquires multiple permits with the specified priority.

This method will wait until all requested permits become available. The operation is atomic - either all permits are acquired or none are.

§Arguments
  • priority - The priority level for this acquisition request
  • n - The number of permits to acquire
§Returns

A future that resolves to either:

  • Ok(RankedSemaphorePermit) - Successfully acquired all permits
  • Err(AcquireError) - Semaphore was closed
§Examples
use ranked_semaphore::RankedSemaphore;

let sem = RankedSemaphore::new_fifo(5);
let permits = sem.acquire_many_with_priority(10, 3).await.unwrap();
assert_eq!(permits.num_permits(), 3);
Source

pub fn try_acquire(&self) -> Result<RankedSemaphorePermit<'_>, TryAcquireError>

Attempts to acquire a single permit without waiting.

This method returns immediately, either with a permit or an error. It will not wait for permits to become available.

§Returns
  • Ok(RankedSemaphorePermit) - Successfully acquired permit
  • Err(TryAcquireError::Closed) - Semaphore is closed
  • Err(TryAcquireError::NoPermits) - No permits available
§Examples
use ranked_semaphore::{RankedSemaphore, TryAcquireError};

let sem = RankedSemaphore::new_fifo(1);
let _permit1 = sem.try_acquire().unwrap();
 
match sem.try_acquire() {
    Ok(_) => panic!("Should not succeed"),
    Err(TryAcquireError::NoPermits) => println!("No permits available"),
    Err(TryAcquireError::Closed) => println!("Semaphore closed"),
};
Source

pub fn try_acquire_many( &self, n: u32, ) -> Result<RankedSemaphorePermit<'_>, TryAcquireError>

Attempts to acquire multiple permits without waiting.

This method returns immediately, either with all requested permits or an error. The operation is atomic - either all permits are acquired or none are.

§Arguments
  • n - The number of permits to acquire
§Returns
  • Ok(RankedSemaphorePermit) - Successfully acquired all permits
  • Err(TryAcquireError::Closed) - Semaphore is closed
  • Err(TryAcquireError::NoPermits) - Insufficient permits available
§Panics

Panics if n exceeds MAX_PERMITS (usize::MAX >> 3).

§Examples
use ranked_semaphore::{RankedSemaphore, TryAcquireError};

let sem = RankedSemaphore::new_fifo(5);
let _permits = sem.try_acquire_many(3).unwrap();
 
match sem.try_acquire_many(5) {
    Ok(_) => panic!("Should not succeed"),
    Err(TryAcquireError::NoPermits) => println!("Not enough permits"),
    Err(TryAcquireError::Closed) => println!("Semaphore closed"),
};
Source

pub fn acquire_owned( self: Arc<Self>, ) -> impl Future<Output = Result<OwnedRankedSemaphorePermit, AcquireError>>

Acquires a single owned permit with default priority (0).

This method returns an owned permit that holds a reference to the semaphore. The semaphore must be wrapped in an Arc to call this method.

§Returns

A future that resolves to either:

  • Ok(OwnedRankedSemaphorePermit) - Successfully acquired permit
  • Err(AcquireError) - Semaphore was closed
§Examples
use ranked_semaphore::RankedSemaphore;
use std::sync::Arc;

let sem = Arc::new(RankedSemaphore::new_fifo(1));
let permit = sem.acquire_owned().await.unwrap();
Source

pub fn acquire_owned_with_priority( self: Arc<Self>, priority: isize, ) -> impl Future<Output = Result<OwnedRankedSemaphorePermit, AcquireError>>

Acquires a single owned permit with the specified priority.

Higher priority values are served first. The semaphore must be wrapped in an Arc to call this method.

§Arguments
  • priority - The priority level for this acquisition request
§Returns

A future that resolves to either:

  • Ok(OwnedRankedSemaphorePermit) - Successfully acquired permit
  • Err(AcquireError) - Semaphore was closed
§Examples
use ranked_semaphore::RankedSemaphore;
use std::sync::Arc;

let sem = Arc::new(RankedSemaphore::new_fifo(1));
let permit = sem.acquire_owned_with_priority(10).await.unwrap();
Source

pub fn acquire_many_owned( self: Arc<Self>, n: u32, ) -> impl Future<Output = Result<OwnedRankedSemaphorePermit, AcquireError>>

Acquires multiple owned permits with default priority (0).

This method will wait until all requested permits become available. The operation is atomic - either all permits are acquired or none are.

§Arguments
  • n - The number of permits to acquire
§Returns

A future that resolves to either:

  • Ok(OwnedRankedSemaphorePermit) - Successfully acquired all permits
  • Err(AcquireError) - Semaphore was closed
§Examples
use ranked_semaphore::RankedSemaphore;
use std::sync::Arc;

let sem = Arc::new(RankedSemaphore::new_fifo(5));
let permits = sem.acquire_many_owned(3).await.unwrap();
assert_eq!(permits.num_permits(), 3);
Source

pub fn acquire_many_owned_with_priority( self: Arc<Self>, priority: isize, n: u32, ) -> impl Future<Output = Result<OwnedRankedSemaphorePermit, AcquireError>>

Acquires multiple owned permits with the specified priority.

This method will wait until all requested permits become available. The operation is atomic - either all permits are acquired or none are.

§Arguments
  • priority - The priority level for this acquisition request
  • n - The number of permits to acquire
§Returns

A future that resolves to either:

  • Ok(OwnedRankedSemaphorePermit) - Successfully acquired all permits
  • Err(AcquireError) - Semaphore was closed
§Examples
use ranked_semaphore::RankedSemaphore;
use std::sync::Arc;

let sem = Arc::new(RankedSemaphore::new_fifo(5));
let permits = sem.acquire_many_owned_with_priority(10, 3).await.unwrap();
assert_eq!(permits.num_permits(), 3);
Source

pub fn try_acquire_owned( self: Arc<Self>, ) -> Result<OwnedRankedSemaphorePermit, TryAcquireError>

Attempts to acquire a single owned permit without waiting.

This method returns immediately, either with a permit or an error. The semaphore must be wrapped in an Arc to call this method.

§Returns
  • Ok(OwnedRankedSemaphorePermit) - Successfully acquired permit
  • Err(TryAcquireError::Closed) - Semaphore is closed
  • Err(TryAcquireError::NoPermits) - No permits available
§Examples
use ranked_semaphore::{RankedSemaphore, TryAcquireError};
use std::sync::Arc;

let sem = Arc::new(RankedSemaphore::new_fifo(1));
let _permit1 = sem.clone().try_acquire_owned().unwrap();
 
match sem.try_acquire_owned() {
    Ok(_) => panic!("Should not succeed"),
    Err(TryAcquireError::NoPermits) => println!("No permits available"),
    Err(TryAcquireError::Closed) => println!("Semaphore closed"),
}
Source

pub fn try_acquire_many_owned( self: Arc<Self>, n: u32, ) -> Result<OwnedRankedSemaphorePermit, TryAcquireError>

Attempts to acquire multiple owned permits without waiting.

This method returns immediately, either with all requested permits or an error. The operation is atomic - either all permits are acquired or none are. The semaphore must be wrapped in an Arc to call this method.

§Arguments
  • n - The number of permits to acquire
§Returns
  • Ok(OwnedRankedSemaphorePermit) - Successfully acquired all permits
  • Err(TryAcquireError::Closed) - Semaphore is closed
  • Err(TryAcquireError::NoPermits) - Insufficient permits available
§Panics

Panics if n exceeds MAX_PERMITS (usize::MAX >> 3).

§Examples
use ranked_semaphore::{RankedSemaphore, TryAcquireError};
use std::sync::Arc;

let sem = Arc::new(RankedSemaphore::new_fifo(5));
let _permits = sem.clone().try_acquire_many_owned(3).unwrap();
 
match sem.try_acquire_many_owned(5) {
    Ok(_) => panic!("Should not succeed"),
    Err(TryAcquireError::NoPermits) => println!("Not enough permits"),
    Err(TryAcquireError::Closed) => println!("Semaphore closed"),
}

Trait Implementations§

Source§

impl Debug for RankedSemaphore

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.