#![allow(dead_code)]
use parking_lot::RwLock;
use std::sync::Arc;
use std::sync::OnceLock;
pub trait SharedResource: Send + Sync + 'static {}
impl<T> SharedResource for T where T: Send + Sync + 'static {}
#[derive(Debug)]
pub struct Shared<T> {
inner: Arc<T>,
}
impl<T> Shared<T> {
pub fn new(value: T) -> Self {
Self {
inner: Arc::new(value),
}
}
pub fn get(&self) -> &T {
&self.inner
}
pub fn arc(&self) -> Arc<T> {
Arc::clone(&self.inner)
}
pub fn strong_count(&self) -> usize {
Arc::strong_count(&self.inner)
}
}
impl<T> Clone for Shared<T> {
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
}
}
}
impl<T> std::ops::Deref for Shared<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[derive(Debug)]
pub struct SharedMut<T> {
inner: Arc<RwLock<T>>,
}
impl<T> SharedMut<T> {
pub fn new(value: T) -> Self {
Self {
inner: Arc::new(RwLock::new(value)),
}
}
pub fn read(&self) -> parking_lot::RwLockReadGuard<'_, T> {
self.inner.read()
}
pub fn write(&self) -> parking_lot::RwLockWriteGuard<'_, T> {
self.inner.write()
}
pub fn try_read(&self) -> Option<parking_lot::RwLockReadGuard<'_, T>> {
self.inner.try_read()
}
pub fn try_write(&self) -> Option<parking_lot::RwLockWriteGuard<'_, T>> {
self.inner.try_write()
}
pub fn arc(&self) -> Arc<RwLock<T>> {
Arc::clone(&self.inner)
}
}
impl<T> Clone for SharedMut<T> {
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
}
}
}
pub struct GlobalShared<T> {
cell: OnceLock<Shared<T>>,
}
impl<T> GlobalShared<T> {
pub const fn new() -> Self {
Self {
cell: OnceLock::new(),
}
}
pub fn init(&self, value: T) -> Result<(), T> {
self.cell.set(Shared::new(value)).map_err(|shared| {
Arc::try_unwrap(shared.inner)
.unwrap_or_else(|_| unreachable!("freshly created Arc should have refcount 1"))
})
}
pub fn get(&self) -> &Shared<T> {
self.cell.get().expect("Global resource not initialized")
}
pub fn try_get(&self) -> Option<&Shared<T>> {
self.cell.get()
}
}
impl<T> Default for GlobalShared<T> {
fn default() -> Self {
Self::new()
}
}
#[macro_export]
macro_rules! global_shared {
($name:ident: $type:ty) => {
static $name: $crate::utils::shared_state::GlobalShared<$type> =
$crate::utils::shared_state::GlobalShared::new();
};
}
pub struct SharedBuilder<T> {
value: Option<T>,
}
impl<T> SharedBuilder<T> {
pub fn new() -> Self {
Self { value: None }
}
pub fn with_value(mut self, value: T) -> Self {
self.value = Some(value);
self
}
pub fn build(self) -> Option<Shared<T>> {
self.value.map(Shared::new)
}
pub fn build_or_panic(self, msg: &str) -> Shared<T> {
self.build().expect(msg)
}
}
impl<T> Default for SharedBuilder<T> {
fn default() -> Self {
Self::new()
}
}
pub mod utils {
use super::*;
pub fn share<T>(value: T) -> Shared<T> {
Shared::new(value)
}
pub fn share_mut<T>(value: T) -> SharedMut<T> {
SharedMut::new(value)
}
pub fn from_arc<T>(arc: Arc<T>) -> Shared<T> {
Shared { inner: arc }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_shared_resource() {
let shared = Shared::new(42);
assert_eq!(*shared.get(), 42);
assert_eq!(*shared, 42);
let cloned = shared.clone();
assert_eq!(*cloned.get(), 42);
assert_eq!(shared.strong_count(), 2);
}
#[test]
fn test_shared_mut_resource() {
let shared = SharedMut::new(42);
{
let read_guard = shared.read();
assert_eq!(*read_guard, 42);
}
{
let mut write_guard = shared.write();
*write_guard = 100;
}
{
let read_guard = shared.read();
assert_eq!(*read_guard, 100);
}
}
#[test]
fn test_global_shared() {
let global: GlobalShared<i32> = GlobalShared::new();
assert!(global.try_get().is_none());
global.init(42).unwrap();
assert_eq!(**global.get(), 42);
assert!(global.init(100).is_err());
}
#[test]
fn test_shared_builder() {
let shared = SharedBuilder::new().with_value(42).build().unwrap();
assert_eq!(*shared.get(), 42);
}
}