Fortune for lazy-rebuild's current commit: Future blessing − 末吉rust-version
parent
01d842f72f
commit
24c0fcb584
@ -0,0 +1,138 @@
|
|||||||
|
use super::*;
|
||||||
|
use std::sync::{Arc,Weak};
|
||||||
|
use std::mem::ManuallyDrop;
|
||||||
|
use crossbeam_queue::ArrayQueue;
|
||||||
|
use std::ops::{
|
||||||
|
Drop,
|
||||||
|
Deref, DerefMut,
|
||||||
|
};
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
|
/// An owned handle to a rented value in a pool.
|
||||||
|
///
|
||||||
|
/// When the handle is dropped, the value will be placed back in the pool if the pool has not already been filled by a replacement(s) or dropped..
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Handle<T>(ManuallyDrop<T>, Weak<ArrayQueue<T>>);
|
||||||
|
|
||||||
|
impl<T> Handle<T>
|
||||||
|
{
|
||||||
|
/// Detach this instance from its owning pool.
|
||||||
|
///
|
||||||
|
/// The value will not be replaced when this handle is dropped.
|
||||||
|
pub fn detach(&mut self)
|
||||||
|
{
|
||||||
|
self.1 = Weak::new();
|
||||||
|
}
|
||||||
|
/// Detach this instance, and insert a new value into the pool in its place.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// `true` if the replacement succeeded.
|
||||||
|
/// `false` if there was no room in the pool, or if the pool has been dropped.
|
||||||
|
pub fn replace(&mut self) -> bool
|
||||||
|
where T: Default
|
||||||
|
{
|
||||||
|
match std::mem::replace(&mut self.1, Weak::new()).upgrade()
|
||||||
|
{
|
||||||
|
Some(v) => v.push(T::default()).is_ok(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Remove the value from the pool.
|
||||||
|
pub fn into_inner(mut self) -> T
|
||||||
|
{
|
||||||
|
self.1 = Weak::new();
|
||||||
|
let val = unsafe {ManuallyDrop::take(&mut self.0)};
|
||||||
|
std::mem::forget(self);
|
||||||
|
val
|
||||||
|
}
|
||||||
|
/// Is the pool still alive?
|
||||||
|
pub fn has_owner(&self) -> bool
|
||||||
|
{
|
||||||
|
self.1.strong_count() > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for Handle<T>
|
||||||
|
{
|
||||||
|
type Target = T;
|
||||||
|
#[inline] fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for Handle<T>
|
||||||
|
{
|
||||||
|
#[inline] fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Borrow<T> for Handle<T>
|
||||||
|
{
|
||||||
|
#[inline] fn borrow(&self) -> &T
|
||||||
|
{
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A self-replacing concurrent pool of rentable objects.
|
||||||
|
///
|
||||||
|
/// # State
|
||||||
|
/// Objects are ephemeral and may be dropped and replaced whenever.
|
||||||
|
/// Do not rely on the state of objects in the pool to remain consistent.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Pool<T>
|
||||||
|
{
|
||||||
|
objects: Arc<ArrayQueue<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for Handle<T>
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(owner) = self.1.upgrade() {
|
||||||
|
let value = unsafe {ManuallyDrop::take(&mut self.0)};
|
||||||
|
drop(owner.push(value));
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
ManuallyDrop::drop(&mut self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Default> Pool<T>
|
||||||
|
{
|
||||||
|
/// Create a new pool with a specific number of objects.
|
||||||
|
/// This number as a maximum capacity will not change.
|
||||||
|
pub fn with_capacity(cap: usize) -> Self
|
||||||
|
{
|
||||||
|
let objects = ArrayQueue::new(cap);
|
||||||
|
for x in
|
||||||
|
std::iter::repeat_with(T::default).take(cap)
|
||||||
|
{
|
||||||
|
assert!(objects.push(x).is_ok());
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
objects: Arc::new(objects),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Create a new pool constructed with the default number of objects.
|
||||||
|
#[inline] pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self::with_capacity(32)
|
||||||
|
}
|
||||||
|
/// Rent an object from the pool of objects.
|
||||||
|
/// If one is not available, a new one is constructed.
|
||||||
|
///
|
||||||
|
/// The object is moved from the pool to a handle.
|
||||||
|
/// It is therefore recommended to box large objects that are in a pool.
|
||||||
|
pub fn rent(&self) -> Handle<T>
|
||||||
|
{
|
||||||
|
if let Some(last) = self.objects.pop()
|
||||||
|
{
|
||||||
|
Handle(ManuallyDrop::new(last), Arc::downgrade(&self.objects))
|
||||||
|
} else {
|
||||||
|
Handle(ManuallyDrop::new(T::default()), Arc::downgrade(&self.objects))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue