use std::sync::Arc;
pub type ShareResult<T> = Result<T, ShareError>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum ShareError {
#[error("This object is closed, calls on it are invalid.")]
Closed,
#[cfg(feature = "unstable-countersigning")]
#[error(transparent)]
ClosureFailed(Box<dyn std::error::Error + Send + Sync>),
}
pub struct Share<T: 'static + Send>(Arc<parking_lot::Mutex<Option<T>>>);
impl<T: 'static + Send> Clone for Share<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: 'static + Send + std::fmt::Debug> std::fmt::Debug for Share<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.share_ref(|s| Ok(f.debug_tuple("Share").field(s).finish()))
.unwrap()
}
}
impl<T: 'static + Send> PartialEq for Share<T> {
fn eq(&self, oth: &Self) -> bool {
Arc::ptr_eq(&self.0, &oth.0)
}
}
impl<T: 'static + Send> Eq for Share<T> {}
impl<T: 'static + Send> std::hash::Hash for Share<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
Arc::as_ptr(&self.0).hash(state);
}
}
impl<T: 'static + Send + Default> Default for Share<T> {
fn default() -> Self {
Self::new(T::default())
}
}
impl<T: 'static + Send> Share<T> {
pub fn new(t: T) -> Self {
Self(Arc::new(parking_lot::Mutex::new(Some(t))))
}
pub fn share_ref<R, F>(&self, f: F) -> ShareResult<R>
where
F: FnOnce(&T) -> ShareResult<R>,
{
let t = self.0.lock();
if t.is_none() {
return Err(ShareError::Closed);
}
f(t.as_ref().unwrap())
}
pub fn share_mut<R, F>(&self, f: F) -> ShareResult<R>
where
F: FnOnce(&mut T, &mut bool) -> ShareResult<R>,
{
let mut t = self.0.lock();
if t.is_none() {
return Err(ShareError::Closed);
}
let mut close = false;
let r = f(t.as_mut().unwrap(), &mut close);
if close {
*t = None;
}
r
}
}