#![doc = include_str!("../README.md")] #![warn(clippy::pedantic)] #![warn(clippy::cargo_common_metadata)] #![warn(clippy::doc_markdown)] #![warn(clippy::missing_panics_doc)] #![warn(clippy::must_use_candidate)] #![warn(clippy::missing_const_for_fn)] #![warn(clippy::semicolon_if_nothing_returned)] #![warn(missing_docs)] #![warn(rustdoc::missing_crate_level_docs)] use std::hash::{Hash, Hasher}; use std::hint::unreachable_unchecked; use std::ops::Deref; use std::sync::{Arc, Weak}; /// A smart pointer that can hold either a static reference or an `Arc`. #[derive(Debug, Eq, PartialOrd, Ord)] #[repr(transparent)] pub struct LArc<'a, T: ?Sized + 'static>(LArcInner<'a, T>); /// The inner representation for hiding the enum variants #[derive(Debug, Eq, PartialOrd, Ord)] enum LArcInner<'a, T: ?Sized + 'static> { /// Variant for holding a static reference. Static(&'static T), /// Variant for holding a lifetime bound reference. Local(&'a T), /// Variant for holding an `Arc` reference. Arc(Arc), } impl Clone for LArc<'_, T> { fn clone(&self) -> Self { LArc(match &self.0 { LArcInner::Static(st) => LArcInner::Static(st), LArcInner::Local(lt) => LArcInner::Local(lt), LArcInner::Arc(arc) => LArcInner::Arc(Arc::clone(arc)), }) } } impl LArc<'static, T> { /// Creates a new `LArc` from a static reference. This is a 'const' function. /// /// # Parameters /// /// * `value`: A reference to a `'static` (static) item of type `T`. It's a static /// reference that can be accessed for the entire program's duration. /// /// # Returns /// /// Returns a new `LArc` instance holding the static reference. pub const fn from_static(value: &'static T) -> Self { LArc(LArcInner::Static(value)) } /// Creates a new `LArc` from an `Arc`. /// /// # Parameters /// /// * `value`: An `Arc` containing a reference-counted shared reference to an item of type `T`. /// /// # Returns /// /// Returns a new `LArc` instance holding the `Arc` reference. pub const fn from_arc(value: Arc) -> Self { LArc(LArcInner::Arc(value)) } } impl LArc<'_, T> { /// Gets the strong reference count. /// /// # Returns /// /// Returns the current strong reference count, or `None` if the reference is static. #[must_use] pub fn strong_count(this: &Self) -> Option { match &this.0 { LArcInner::Static(_) | LArcInner::Local(_) => None, LArcInner::Arc(arc) => Some(Arc::strong_count(arc)), } } /// Gets the weak reference count. /// /// # Returns /// /// Returns the current weak reference count, or `None` if the reference is static. #[must_use] pub fn weak_count(this: &Self) -> Option { match &this.0 { LArcInner::Static(_) | LArcInner::Local(_) => None, LArcInner::Arc(arc) => Some(Arc::weak_count(arc)), } } /// Gets a mutable reference to the inner value. /// /// # Parameters /// /// * `this`: A mutable reference to a `LArc` instance. /// /// # Returns /// /// Returns a `Some(&mut T)` when the underlying `LArc` stores an `Arc` with a strong /// count of one. Otherwise `None` is returned. pub fn get_mut(this: &mut Self) -> Option<&mut T> { match this.0 { LArcInner::Static(_) | LArcInner::Local(_) => None, LArcInner::Arc(ref mut arc) => Arc::get_mut(arc), } } /// Returns a raw pointer to the inner data. /// /// If the underlying data is in an `Arc`, this method returns a pointer to the data. /// If the data is static, it returns a pointer to the static reference. /// /// Care should be taken when using the raw pointer obtained from this method, /// especially when the underlying data is in an `Arc`. It's essential to ensure that the `LArc` /// or `Arc` remains alive while the raw pointer is in use. Dereferencing a raw pointer after /// the `LArc` or `Arc` has been dropped will lead to undefined behavior. /// /// # Returns /// /// Returns a raw pointer to the inner data. #[must_use] pub fn as_ptr(this: &Self) -> *const T { match this.0 { LArcInner::Static(st) => st, LArcInner::Local(lt) => lt, LArcInner::Arc(ref arc) => &**arc, } } #[cfg(test)] pub(crate) const fn is_static(&self) -> bool { matches!(self, LArc(LArcInner::Static(_))) } #[cfg(test)] pub(crate) const fn is_arc(&self) -> bool { matches!(self, LArc(LArcInner::Arc(_))) } } impl<'a, T: ?Sized> LArc<'a, T> { /// Creates a new `LArc` that has a lifetime bound on the passed value. /// /// # Parameters /// /// * `value`: A reference to a item of type `T`. /// /// # Returns /// /// Returns a new `LArc` instance holding the static reference. pub const fn from_local(value: &'a T) -> Self { LArc(LArcInner::Local(value)) } /// Downgrades this `LArc` to a `LWeak`. /// /// # Parameters /// /// * `this`: A reference to a `LArc` instance. /// /// # Returns /// /// Returns a weak reference (`LWeak`) corresponding to the provided `LArc`. #[must_use] pub fn downgrade(this: &Self) -> LWeak<'a, T> { match &this.0 { LArcInner::Static(st) => LWeak(LWeakInner::Static(st)), LArcInner::Local(lt) => LWeak(LWeakInner::Local(lt)), LArcInner::Arc(arc) => LWeak(LWeakInner::Weak(Arc::downgrade(arc))), } } } impl LArc<'_, T> { /// Converts a reference counted `LArc` into a static refencing `LArc`. This will leak /// the allocated memory. When the `LArc` is already backed by a static reference then /// this does nothing. /// /// # Parameters /// /// * `this`: A mutable reference to a `LArc` instance. /// /// # Returns /// /// Returns a `'static` reference to the data. pub fn make_static(this: &mut Self) -> &'static T { match this.0 { LArcInner::Static(st) => st, LArcInner::Local(lt) => { let st = unsafe { // SAFETY: we leak the box here, having T being 'static should make this sound. &*Box::into_raw(Box::new(lt.clone())) }; *this = LArc(LArcInner::Static(st)); st } LArcInner::Arc(ref mut arc) => { let ptr = Arc::into_raw(arc.clone()); unsafe { // SAFETY: we leak the Arc here, having T being 'static should make this sound. Arc::increment_strong_count(ptr); *this = LArc(LArcInner::Static(&*ptr)); &*ptr } } } } /// Converts a reference counted `LArc` into a static refencing `LArc`. This will leak the /// allocated memory. This consumes the supplied `LArc<'local, T>` and returns a /// `LArc<'static, T>` /// /// # Parameters /// /// * `this`: A `LArc` instance. /// /// # Returns /// /// Returns a new `LArc` with `'static` lifetime. #[must_use] pub fn into_static(mut this: Self) -> LArc<'static, T> { LArc(LArcInner::Static(LArc::make_static(&mut this))) } } impl LArc<'_, T> where T: Sized + Clone, Arc: From, { /// Makes a mutable reference to the inner value, cloning if necessary. /// /// # Parameters /// /// * `this`: A mutable reference to a `LArc` instance. /// /// # Returns /// /// Returns a mutable reference to the inner value. pub fn make_mut(this: &mut Self) -> &mut T { match this.0 { LArcInner::Static(r) | LArcInner::Local(r) => { let arc = Arc::from(r.clone()); *this = LArc(LArcInner::Arc(arc)); } LArcInner::Arc(_) => { /* NOP */ } } let LArcInner::Arc(ref mut arc) = this.0 else { unsafe { // SAFETY: we just replaced *this with an Arc unreachable_unchecked(); } }; Arc::make_mut(&mut *arc) } /// Converts `LArc` into a reference counted `LArc` with `'static` lifetime that can be /// mutated. References become converted to an `Arc`, the arc is made mutable (content /// cloned when the refcount is bigger than one) /// /// # Parameters /// /// * `this`: A `LArc` instance. /// /// # Returns /// /// Returns a new `LArc` with `'static` lifetime backed by an `Arc`. #[must_use] pub fn into_mut(this: Self) -> LArc<'static, T> { let mut arc = match this.0 { LArcInner::Static(r) | LArcInner::Local(r) => Arc::from(r.clone()), LArcInner::Arc(arc) => arc, }; Arc::make_mut(&mut arc); LArc(LArcInner::Arc(arc)) } } /// Creates a new `LArc` from a reference. This `LArc` will have its lifetime bound to the /// supplied reference. When the reference is `'static` then use the `LArc::from_static()` /// constructor. /// /// # Parameters /// /// * `value`: A reference to a item of type `T`. /// /// # Returns /// /// Returns a new `LArc` instance holding the reference. impl<'a, T: ?Sized> From<&'a T> for LArc<'a, T> { fn from(value: &'a T) -> Self { LArc::from_local(value) } } /// Creates a new `LArc` from an `Arc`. /// /// # Parameters /// /// * `value`: An `Arc` containing a reference-counted shared reference to an item of type /// `T`. /// /// # Returns /// /// Returns a new `LArc` instance holding the `Arc` reference. impl From> for LArc<'_, T> { fn from(value: Arc) -> Self { LArc::from_arc(value) } } impl Deref for LArc<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } } impl Deref for LArcInner<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { match self { LArcInner::Static(st) => st, LArcInner::Local(lt) => lt, LArcInner::Arc(arc) => arc, } } } impl AsRef for LArc<'_, T> { fn as_ref(&self) -> &T { &self.0 } } impl PartialEq for LArcInner<'_, T> { #[inline] fn eq(&self, other: &Self) -> bool { (**self).eq(other) } } impl PartialEq for LArc<'_, T> { #[inline] fn eq(&self, other: &Self) -> bool { (**self).eq(other) } } #[test] fn partialeq() { let value = 42; let larc = LArc::from(&value); assert_eq!(*larc, value); assert_eq!(value, *larc); assert_eq!(larc, larc); assert_eq!(&larc, &larc); } impl Hash for LArcInner<'_, T> { #[inline] fn hash(&self, state: &mut H) { (**self).hash(state); } } /// A weak smart pointer may hold either a static reference or an `Arc`. /// For accessing the stored value a `Weak` pointer must be upgraded first. #[derive(Debug)] pub struct LWeak<'a, T: ?Sized + 'static>(LWeakInner<'a, T>); /// The inner representation for hiding the enum variants #[derive(Debug)] enum LWeakInner<'a, T: ?Sized + 'static> { /// Variant for holding a static reference. Static(&'static T), /// Variant for holding a lifetime bound reference. Local(&'a T), /// Variant for holding an `Arc` reference. Weak(Weak), } impl Clone for LWeak<'_, T> { fn clone(&self) -> Self { match &self.0 { LWeakInner::Static(st) => LWeak(LWeakInner::Static(st)), LWeakInner::Local(lt) => LWeak(LWeakInner::Local(lt)), LWeakInner::Weak(weak) => LWeak(LWeakInner::Weak(Weak::clone(weak))), } } } impl LWeak<'_, T> { /// Creates a new weak empty reference. /// /// # Returns /// /// Returns a new `LWeak` instance. Empty references can never be upgraded. #[must_use] pub const fn new() -> Self { LWeak(LWeakInner::Weak(Weak::new())) } } impl LWeak<'_, T> { /// Attempts to upgrade the weak reference to a strong reference. /// /// # Parameters /// /// * `this`: A reference to a `LWeak` instance. /// /// # Returns /// /// Returns an `Option`: /// - `Some(LArc)` if the weak reference can be upgraded to a strong reference. /// - `None` if the weak reference is no longer valid. /// /// Note that `'static` references can be always upgraded. #[must_use] pub fn upgrade(this: &Self) -> Option> { match &this.0 { LWeakInner::Static(st) => Some(LArc(LArcInner::Static(st))), LWeakInner::Local(lt) => Some(LArc(LArcInner::Local(lt))), LWeakInner::Weak(weak) => Weak::upgrade(weak).map(|arc| LArc(LArcInner::Arc(arc))), } } /// Gets the strong reference count. /// /// # Returns /// /// Returns the current strong reference count, or `None` if the reference is static. #[must_use] pub fn strong_count(this: &Self) -> Option { match &this.0 { LWeakInner::Static(_) | LWeakInner::Local(_) => None, LWeakInner::Weak(weak) => Some(Weak::strong_count(weak)), } } /// Gets the weak reference count. /// /// # Returns /// /// Returns the current weak reference count, or `None` if the reference is static. #[must_use] pub fn weak_count(this: &Self) -> Option { match &this.0 { LWeakInner::Static(_) | LWeakInner::Local(_) => None, LWeakInner::Weak(weak) => Some(Weak::weak_count(weak)), } } } impl Default for LWeak<'_, T> { fn default() -> Self { LWeak::new() } } #[test] fn smoke() { let st = LArc::from_static("foobar"); assert!(st.is_static()); println!("{st:?}"); let arc = LArc::from_arc(Arc::::from("foobar")); assert!(arc.is_arc()); } #[test] fn from() { let _st = LArc::from("foobar"); //assert!(st.is_static()); let arc = LArc::from(Arc::::from("foobar")); assert!(arc.is_arc()); } #[test] fn deref() { let st = LArc::from("foobar"); assert_eq!(&*st, "foobar"); let arc = LArc::from(Arc::::from("foobar")); assert_eq!(&*arc, "foobar"); } #[test] fn clone() { let st = LArc::from_static("foobar"); let st2 = st.clone(); assert!(st2.is_static()); assert_eq!(&*st2, "foobar"); let arc = LArc::from_arc(Arc::::from("foobar")); let arc2 = arc.clone(); assert!(arc2.is_arc()); assert_eq!(&*arc2, "foobar"); } #[test] fn make_mut() { let mut starc = LArc::from_static(&1234); *LArc::make_mut(&mut starc) = 23456; assert!(starc.is_arc()); assert_eq!(*starc, 23456); } #[cfg_attr(miri, ignore)] #[test] fn make_static() { let mut arc = LArc::from_arc(Arc::from(1234)); let s: &'static i32 = LArc::make_static(&mut arc); assert!(arc.is_static()); assert_eq!(*arc, 1234); assert_eq!(*arc, *s); } #[cfg_attr(miri, ignore)] #[test] fn into_static() { let outer_static_larc; { let local = 1234; let local_larc = LArc::from_local(&local); let static_larc = LArc::into_static(local_larc); outer_static_larc = Some(static_larc.clone()); } assert_eq!(*outer_static_larc.unwrap(), 1234); } #[test] fn as_ref() { let st = LArc::from_static("foobar"); assert_eq!(st.as_ref(), "foobar"); let arc = LArc::from_arc(Arc::::from("foobar")); assert_eq!(arc.as_ref(), "foobar"); }