larc/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(clippy::pedantic)]
3#![warn(clippy::cargo_common_metadata)]
4#![warn(clippy::doc_markdown)]
5#![warn(clippy::missing_panics_doc)]
6#![warn(clippy::must_use_candidate)]
7#![warn(clippy::missing_const_for_fn)]
8#![warn(clippy::semicolon_if_nothing_returned)]
9#![warn(missing_docs)]
10#![warn(rustdoc::missing_crate_level_docs)]
11
12use std::hash::{Hash, Hasher};
13use std::hint::unreachable_unchecked;
14use std::ops::Deref;
15use std::sync::{Arc, Weak};
16
17/// A smart pointer that can hold either a static reference or an `Arc`.
18#[derive(Debug, Eq, PartialOrd, Ord)]
19#[repr(transparent)]
20pub struct LArc<'a, T: ?Sized + 'static>(LArcInner<'a, T>);
21
22/// The inner representation for hiding the enum variants
23#[derive(Debug, Eq, PartialOrd, Ord)]
24enum LArcInner<'a, T: ?Sized + 'static> {
25    /// Variant for holding a static reference.
26    Static(&'static T),
27    /// Variant for holding a lifetime bound reference.
28    Local(&'a T),
29    /// Variant for holding an `Arc` reference.
30    Arc(Arc<T>),
31}
32
33impl<T: ?Sized> Clone for LArc<'_, T> {
34    fn clone(&self) -> Self {
35        LArc(match &self.0 {
36            LArcInner::Static(st) => LArcInner::Static(st),
37            LArcInner::Local(lt) => LArcInner::Local(lt),
38            LArcInner::Arc(arc) => LArcInner::Arc(Arc::clone(arc)),
39        })
40    }
41}
42
43impl<T: ?Sized> LArc<'static, T> {
44    /// Creates a new `LArc` from a static reference. This is a 'const' function.
45    ///
46    /// # Parameters
47    ///
48    /// * `value`: A reference to a `'static` (static) item of type `T`. It's a static
49    /// reference that can be accessed for the entire program's duration.
50    ///
51    /// # Returns
52    ///
53    /// Returns a new `LArc` instance holding the static reference.
54    pub const fn from_static(value: &'static T) -> Self {
55        LArc(LArcInner::Static(value))
56    }
57
58    /// Creates a new `LArc` from an `Arc`.
59    ///
60    /// # Parameters
61    ///
62    /// * `value`: An `Arc` containing a reference-counted shared reference to an item of type `T`.
63    ///
64    /// # Returns
65    ///
66    /// Returns a new `LArc` instance holding the `Arc` reference.
67    pub const fn from_arc(value: Arc<T>) -> Self {
68        LArc(LArcInner::Arc(value))
69    }
70}
71
72impl<T: ?Sized> LArc<'_, T> {
73    /// Gets the strong reference count.
74    ///
75    /// # Returns
76    ///
77    /// Returns the current strong reference count, or `None` if the reference is static.
78    #[must_use]
79    pub fn strong_count(this: &Self) -> Option<usize> {
80        match &this.0 {
81            LArcInner::Static(_) | LArcInner::Local(_) => None,
82            LArcInner::Arc(arc) => Some(Arc::strong_count(arc)),
83        }
84    }
85
86    /// Gets the weak reference count.
87    ///
88    /// # Returns
89    ///
90    /// Returns the current weak reference count, or `None` if the reference is static.
91    #[must_use]
92    pub fn weak_count(this: &Self) -> Option<usize> {
93        match &this.0 {
94            LArcInner::Static(_) | LArcInner::Local(_) => None,
95            LArcInner::Arc(arc) => Some(Arc::weak_count(arc)),
96        }
97    }
98
99    /// Gets a mutable reference to the inner value.
100    ///
101    /// # Parameters
102    ///
103    /// * `this`: A mutable reference to a `LArc<T>` instance.
104    ///
105    /// # Returns
106    ///
107    /// Returns a `Some(&mut T)` when the underlying `LArc` stores an `Arc` with a strong
108    /// count of one. Otherwise `None` is returned.
109    pub fn get_mut(this: &mut Self) -> Option<&mut T> {
110        match this.0 {
111            LArcInner::Static(_) | LArcInner::Local(_) => None,
112            LArcInner::Arc(ref mut arc) => Arc::get_mut(arc),
113        }
114    }
115
116    /// Returns a raw pointer to the inner data.
117    ///
118    /// If the underlying data is in an `Arc`, this method returns a pointer to the data.
119    /// If the data is static, it returns a pointer to the static reference.
120    ///
121    /// Care should be taken when using the raw pointer obtained from this method,
122    /// especially when the underlying data is in an `Arc`. It's essential to ensure that the `LArc`
123    /// or `Arc` remains alive while the raw pointer is in use. Dereferencing a raw pointer after
124    /// the `LArc` or `Arc` has been dropped will lead to undefined behavior.
125    ///
126    /// # Returns
127    ///
128    /// Returns a raw pointer to the inner data.
129    #[must_use]
130    pub fn as_ptr(this: &Self) -> *const T {
131        match this.0 {
132            LArcInner::Static(st) => st,
133            LArcInner::Local(lt) => lt,
134            LArcInner::Arc(ref arc) => &**arc,
135        }
136    }
137
138    #[cfg(test)]
139    pub(crate) const fn is_static(&self) -> bool {
140        matches!(self, LArc(LArcInner::Static(_)))
141    }
142
143    #[cfg(test)]
144    pub(crate) const fn is_arc(&self) -> bool {
145        matches!(self, LArc(LArcInner::Arc(_)))
146    }
147}
148
149impl<'a, T: ?Sized> LArc<'a, T> {
150    /// Creates a new `LArc` that has a lifetime bound on the passed value.
151    ///
152    /// # Parameters
153    ///
154    /// * `value`: A reference to a  item of type `T`.
155    ///
156    /// # Returns
157    ///
158    /// Returns a new `LArc` instance holding the static reference.
159    pub const fn from_local(value: &'a T) -> Self {
160        LArc(LArcInner::Local(value))
161    }
162
163    /// Downgrades this `LArc` to a `LWeak`.
164    ///
165    /// # Parameters
166    ///
167    /// * `this`: A reference to a `LArc<T>` instance.
168    ///
169    /// # Returns
170    ///
171    /// Returns a weak reference (`LWeak`) corresponding to the provided `LArc`.
172    #[must_use]
173    pub fn downgrade(this: &Self) -> LWeak<'a, T> {
174        match &this.0 {
175            LArcInner::Static(st) => LWeak(LWeakInner::Static(st)),
176            LArcInner::Local(lt) => LWeak(LWeakInner::Local(lt)),
177            LArcInner::Arc(arc) => LWeak(LWeakInner::Weak(Arc::downgrade(arc))),
178        }
179    }
180}
181
182impl<T: Clone + 'static> LArc<'_, T> {
183    /// Converts a reference counted `LArc` into a static refencing `LArc`.  This will leak
184    /// the allocated memory. When the `LArc` is already backed by a static reference then
185    /// this does nothing.
186    ///
187    /// # Parameters
188    ///
189    /// * `this`: A mutable reference to a `LArc<T>` instance.
190    ///
191    /// # Returns
192    ///
193    /// Returns a `'static` reference to the data.
194    pub fn make_static(this: &mut Self) -> &'static T {
195        match this.0 {
196            LArcInner::Static(st) => st,
197            LArcInner::Local(lt) => {
198                let st = unsafe {
199                    // SAFETY: we leak the box here, having T being 'static should make this sound.
200                    &*Box::into_raw(Box::new(lt.clone()))
201                };
202                *this = LArc(LArcInner::Static(st));
203                st
204            }
205            LArcInner::Arc(ref mut arc) => {
206                let ptr = Arc::into_raw(arc.clone());
207                unsafe {
208                    // SAFETY: we leak the Arc here, having T being 'static should make this sound.
209                    Arc::increment_strong_count(ptr);
210                    *this = LArc(LArcInner::Static(&*ptr));
211                    &*ptr
212                }
213            }
214        }
215    }
216
217    /// Converts a reference counted `LArc` into a static refencing `LArc`. This will leak the
218    /// allocated memory. This consumes the supplied `LArc<'local, T>` and returns a
219    /// `LArc<'static, T>`
220    ///
221    /// # Parameters
222    ///
223    /// * `this`: A `LArc<T>` instance.
224    ///
225    /// # Returns
226    ///
227    /// Returns a new `LArc` with `'static` lifetime.
228    #[must_use]
229    pub fn into_static(mut this: Self) -> LArc<'static, T> {
230        LArc(LArcInner::Static(LArc::make_static(&mut this)))
231    }
232}
233
234impl<T> LArc<'_, T>
235where
236    T: Sized + Clone,
237    Arc<T>: From<T>,
238{
239    /// Makes a mutable reference to the inner value, cloning if necessary.
240    ///
241    /// # Parameters
242    ///
243    /// * `this`: A mutable reference to a `LArc<T>` instance.
244    ///
245    /// # Returns
246    ///
247    /// Returns a mutable reference to the inner value.
248    pub fn make_mut(this: &mut Self) -> &mut T {
249        match this.0 {
250            LArcInner::Static(r) | LArcInner::Local(r) => {
251                let arc = Arc::from(r.clone());
252                *this = LArc(LArcInner::Arc(arc));
253            }
254            LArcInner::Arc(_) => { /* NOP */ }
255        }
256        let LArcInner::Arc(ref mut arc) = this.0 else {
257            unsafe {
258                // SAFETY: we just replaced *this with an Arc
259                unreachable_unchecked();
260            }
261        };
262        Arc::make_mut(&mut *arc)
263    }
264
265    /// Converts `LArc` into a reference counted `LArc` with `'static` lifetime that can be
266    /// mutated. References become converted to an `Arc`, the arc is made mutable (content
267    /// cloned when the refcount is bigger than one)
268    ///
269    /// # Parameters
270    ///
271    /// * `this`: A `LArc<T>` instance.
272    ///
273    /// # Returns
274    ///
275    /// Returns a new `LArc` with `'static` lifetime backed by an `Arc`.
276    #[must_use]
277    pub fn into_mut(this: Self) -> LArc<'static, T> {
278        let mut arc = match this.0 {
279            LArcInner::Static(r) | LArcInner::Local(r) => Arc::from(r.clone()),
280            LArcInner::Arc(arc) => arc,
281        };
282        Arc::make_mut(&mut arc);
283        LArc(LArcInner::Arc(arc))
284    }
285}
286
287/// Creates a new `LArc` from a reference. This `LArc` will have its lifetime bound to the
288/// supplied reference. When the reference is `'static` then use the `LArc::from_static()`
289/// constructor.
290///
291/// # Parameters
292///
293/// * `value`: A reference to a item of type `T`.
294///
295/// # Returns
296///
297/// Returns a new `LArc` instance holding the reference.
298impl<'a, T: ?Sized> From<&'a T> for LArc<'a, T> {
299    fn from(value: &'a T) -> Self {
300        LArc::from_local(value)
301    }
302}
303
304/// Creates a new `LArc` from an `Arc`.
305///
306/// # Parameters
307///
308/// * `value`: An `Arc` containing a reference-counted shared reference to an item of type
309/// `T`.
310///
311/// # Returns
312///
313/// Returns a new `LArc` instance holding the `Arc` reference.
314impl<T: ?Sized> From<Arc<T>> for LArc<'_, T> {
315    fn from(value: Arc<T>) -> Self {
316        LArc::from_arc(value)
317    }
318}
319
320impl<T: ?Sized> Deref for LArc<'_, T> {
321    type Target = T;
322
323    fn deref(&self) -> &Self::Target {
324        &self.0
325    }
326}
327
328impl<T: ?Sized> Deref for LArcInner<'_, T> {
329    type Target = T;
330
331    fn deref(&self) -> &Self::Target {
332        match self {
333            LArcInner::Static(st) => st,
334            LArcInner::Local(lt) => lt,
335            LArcInner::Arc(arc) => arc,
336        }
337    }
338}
339
340impl<T: ?Sized> AsRef<T> for LArc<'_, T> {
341    fn as_ref(&self) -> &T {
342        &self.0
343    }
344}
345
346impl<T: PartialEq + ?Sized> PartialEq for LArcInner<'_, T> {
347    #[inline]
348    fn eq(&self, other: &Self) -> bool {
349        (**self).eq(other)
350    }
351}
352
353impl<T: PartialEq + ?Sized> PartialEq for LArc<'_, T> {
354    #[inline]
355    fn eq(&self, other: &Self) -> bool {
356        (**self).eq(other)
357    }
358}
359
360#[test]
361fn partialeq() {
362    let value = 42;
363    let larc = LArc::from(&value);
364
365    assert_eq!(*larc, value);
366    assert_eq!(value, *larc);
367    assert_eq!(larc, larc);
368    assert_eq!(&larc, &larc);
369}
370
371impl<T: Hash> Hash for LArcInner<'_, T> {
372    #[inline]
373    fn hash<H: Hasher>(&self, state: &mut H) {
374        (**self).hash(state);
375    }
376}
377
378/// A weak smart pointer may hold either a static reference or an `Arc`.
379/// For accessing the stored value a `Weak` pointer must be upgraded first.
380#[derive(Debug)]
381pub struct LWeak<'a, T: ?Sized + 'static>(LWeakInner<'a, T>);
382
383/// The inner representation for hiding the enum variants
384#[derive(Debug)]
385enum LWeakInner<'a, T: ?Sized + 'static> {
386    /// Variant for holding a static reference.
387    Static(&'static T),
388    /// Variant for holding a lifetime bound reference.
389    Local(&'a T),
390    /// Variant for holding an `Arc` reference.
391    Weak(Weak<T>),
392}
393
394impl<T: ?Sized + 'static> Clone for LWeak<'_, T> {
395    fn clone(&self) -> Self {
396        match &self.0 {
397            LWeakInner::Static(st) => LWeak(LWeakInner::Static(st)),
398            LWeakInner::Local(lt) => LWeak(LWeakInner::Local(lt)),
399            LWeakInner::Weak(weak) => LWeak(LWeakInner::Weak(Weak::clone(weak))),
400        }
401    }
402}
403
404impl<T> LWeak<'_, T> {
405    /// Creates a new weak empty reference.
406    ///
407    /// # Returns
408    ///
409    /// Returns a new `LWeak` instance. Empty references can never be upgraded.
410    #[must_use]
411    pub const fn new() -> Self {
412        LWeak(LWeakInner::Weak(Weak::new()))
413    }
414}
415
416impl<T: ?Sized> LWeak<'_, T> {
417    /// Attempts to upgrade the weak reference to a strong reference.
418    ///
419    /// # Parameters
420    ///
421    /// * `this`: A reference to a `LWeak<T>` instance.
422    ///
423    /// # Returns
424    ///
425    /// Returns an `Option`:
426    /// - `Some(LArc<T>)` if the weak reference can be upgraded to a strong reference.
427    /// - `None` if the weak reference is no longer valid.
428    ///
429    /// Note that `'static` references can be always upgraded.
430    #[must_use]
431    pub fn upgrade(this: &Self) -> Option<LArc<T>> {
432        match &this.0 {
433            LWeakInner::Static(st) => Some(LArc(LArcInner::Static(st))),
434            LWeakInner::Local(lt) => Some(LArc(LArcInner::Local(lt))),
435            LWeakInner::Weak(weak) => Weak::upgrade(weak).map(|arc| LArc(LArcInner::Arc(arc))),
436        }
437    }
438
439    /// Gets the strong reference count.
440    ///
441    /// # Returns
442    ///
443    /// Returns the current strong reference count, or `None` if the reference is static.
444    #[must_use]
445    pub fn strong_count(this: &Self) -> Option<usize> {
446        match &this.0 {
447            LWeakInner::Static(_) | LWeakInner::Local(_) => None,
448            LWeakInner::Weak(weak) => Some(Weak::strong_count(weak)),
449        }
450    }
451
452    /// Gets the weak reference count.
453    ///
454    /// # Returns
455    ///
456    /// Returns the current weak reference count, or `None` if the reference is static.
457    #[must_use]
458    pub fn weak_count(this: &Self) -> Option<usize> {
459        match &this.0 {
460            LWeakInner::Static(_) | LWeakInner::Local(_) => None,
461            LWeakInner::Weak(weak) => Some(Weak::weak_count(weak)),
462        }
463    }
464}
465
466impl<T> Default for LWeak<'_, T> {
467    fn default() -> Self {
468        LWeak::new()
469    }
470}
471
472#[test]
473fn smoke() {
474    let st = LArc::from_static("foobar");
475    assert!(st.is_static());
476    println!("{st:?}");
477
478    let arc = LArc::from_arc(Arc::<str>::from("foobar"));
479    assert!(arc.is_arc());
480}
481
482#[test]
483fn from() {
484    let _st = LArc::from("foobar");
485    //assert!(st.is_static());
486
487    let arc = LArc::from(Arc::<str>::from("foobar"));
488    assert!(arc.is_arc());
489}
490
491#[test]
492fn deref() {
493    let st = LArc::from("foobar");
494    assert_eq!(&*st, "foobar");
495
496    let arc = LArc::from(Arc::<str>::from("foobar"));
497    assert_eq!(&*arc, "foobar");
498}
499
500#[test]
501fn clone() {
502    let st = LArc::from_static("foobar");
503    let st2 = st.clone();
504    assert!(st2.is_static());
505    assert_eq!(&*st2, "foobar");
506
507    let arc = LArc::from_arc(Arc::<str>::from("foobar"));
508    let arc2 = arc.clone();
509    assert!(arc2.is_arc());
510    assert_eq!(&*arc2, "foobar");
511}
512
513#[test]
514fn make_mut() {
515    let mut starc = LArc::from_static(&1234);
516
517    *LArc::make_mut(&mut starc) = 23456;
518
519    assert!(starc.is_arc());
520    assert_eq!(*starc, 23456);
521}
522
523#[cfg_attr(miri, ignore)]
524#[test]
525fn make_static() {
526    let mut arc = LArc::from_arc(Arc::from(1234));
527    let s: &'static i32 = LArc::make_static(&mut arc);
528
529    assert!(arc.is_static());
530    assert_eq!(*arc, 1234);
531    assert_eq!(*arc, *s);
532}
533
534#[cfg_attr(miri, ignore)]
535#[test]
536fn into_static() {
537    let outer_static_larc;
538    {
539        let local = 1234;
540        let local_larc = LArc::from_local(&local);
541        let static_larc = LArc::into_static(local_larc);
542        outer_static_larc = Some(static_larc.clone());
543    }
544    assert_eq!(*outer_static_larc.unwrap(), 1234);
545}
546
547#[test]
548fn as_ref() {
549    let st = LArc::from_static("foobar");
550    assert_eq!(st.as_ref(), "foobar");
551
552    let arc = LArc::from_arc(Arc::<str>::from("foobar"));
553    assert_eq!(arc.as_ref(), "foobar");
554}