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
impl RankedSemaphore
Sourcepub const MAX_PERMITS: usize = 2_305_843_009_213_693_951usize
pub const MAX_PERMITS: usize = 2_305_843_009_213_693_951usize
Maximum permits (reserve 3 bits for flags, same as tokio)
Sourcepub fn new_fifo(permits: usize) -> Self
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);Sourcepub fn new_lifo(permits: usize) -> Self
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);Sourcepub fn new(permits: usize, default_strategy: QueueStrategy) -> Self
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 availabledefault_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);Sourcepub fn new_with_config(permits: usize, config: PriorityConfig) -> Self
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 availableconfig- 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);Sourcepub fn available_permits(&self) -> usize
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);Sourcepub fn is_closed(&self) -> bool
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());Sourcepub fn add_permits(&self, added: usize)
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);Sourcepub fn close(&self)
pub fn close(&self)
Closes the semaphore and cancels all pending waiters.
After calling this method:
- No new permits will be issued
- All pending
acquireoperations will returnAcquireError::Closed - All
try_acquireoperations will returnTryAcquireError::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());Sourcepub fn forget_permits(&self, n: usize) -> usize
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
impl RankedSemaphore
Sourcepub fn acquire(
&self,
) -> impl Future<Output = Result<RankedSemaphorePermit<'_>, AcquireError>>
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 permitErr(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 droppedSourcepub fn acquire_with_priority(
&self,
priority: isize,
) -> impl Future<Output = Result<RankedSemaphorePermit<'_>, AcquireError>>
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 permitErr(AcquireError)- Semaphore was closed
§Examples
use ranked_semaphore::RankedSemaphore;
let sem = RankedSemaphore::new_fifo(1);
let permit = sem.acquire_with_priority(10).await.unwrap();Sourcepub fn acquire_many(
&self,
n: u32,
) -> impl Future<Output = Result<RankedSemaphorePermit<'_>, AcquireError>>
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 permitsErr(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);Sourcepub fn acquire_many_with_priority(
&self,
priority: isize,
n: u32,
) -> impl Future<Output = Result<RankedSemaphorePermit<'_>, AcquireError>>
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 requestn- The number of permits to acquire
§Returns
A future that resolves to either:
Ok(RankedSemaphorePermit)- Successfully acquired all permitsErr(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);Sourcepub fn try_acquire(&self) -> Result<RankedSemaphorePermit<'_>, TryAcquireError>
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 permitErr(TryAcquireError::Closed)- Semaphore is closedErr(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"),
};Sourcepub fn try_acquire_many(
&self,
n: u32,
) -> Result<RankedSemaphorePermit<'_>, TryAcquireError>
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 permitsErr(TryAcquireError::Closed)- Semaphore is closedErr(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"),
};Sourcepub fn acquire_owned(
self: Arc<Self>,
) -> impl Future<Output = Result<OwnedRankedSemaphorePermit, AcquireError>>
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 permitErr(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();Sourcepub fn acquire_owned_with_priority(
self: Arc<Self>,
priority: isize,
) -> impl Future<Output = Result<OwnedRankedSemaphorePermit, AcquireError>>
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 permitErr(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();Sourcepub fn acquire_many_owned(
self: Arc<Self>,
n: u32,
) -> impl Future<Output = Result<OwnedRankedSemaphorePermit, AcquireError>>
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 permitsErr(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);Sourcepub fn acquire_many_owned_with_priority(
self: Arc<Self>,
priority: isize,
n: u32,
) -> impl Future<Output = Result<OwnedRankedSemaphorePermit, AcquireError>>
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 requestn- The number of permits to acquire
§Returns
A future that resolves to either:
Ok(OwnedRankedSemaphorePermit)- Successfully acquired all permitsErr(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);Sourcepub fn try_acquire_owned(
self: Arc<Self>,
) -> Result<OwnedRankedSemaphorePermit, TryAcquireError>
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 permitErr(TryAcquireError::Closed)- Semaphore is closedErr(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"),
}Sourcepub fn try_acquire_many_owned(
self: Arc<Self>,
n: u32,
) -> Result<OwnedRankedSemaphorePermit, TryAcquireError>
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 permitsErr(TryAcquireError::Closed)- Semaphore is closedErr(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"),
}