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#[derive(Debug, Eq, PartialOrd, Ord)]
19#[repr(transparent)]
20pub struct LArc<'a, T: ?Sized + 'static>(LArcInner<'a, T>);
21
22#[derive(Debug, Eq, PartialOrd, Ord)]
24enum LArcInner<'a, T: ?Sized + 'static> {
25 Static(&'static T),
27 Local(&'a T),
29 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 pub const fn from_static(value: &'static T) -> Self {
55 LArc(LArcInner::Static(value))
56 }
57
58 pub const fn from_arc(value: Arc<T>) -> Self {
68 LArc(LArcInner::Arc(value))
69 }
70}
71
72impl<T: ?Sized> LArc<'_, T> {
73 #[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 #[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 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 #[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 pub const fn from_local(value: &'a T) -> Self {
160 LArc(LArcInner::Local(value))
161 }
162
163 #[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 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 &*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 Arc::increment_strong_count(ptr);
210 *this = LArc(LArcInner::Static(&*ptr));
211 &*ptr
212 }
213 }
214 }
215 }
216
217 #[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 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(_) => { }
255 }
256 let LArcInner::Arc(ref mut arc) = this.0 else {
257 unsafe {
258 unreachable_unchecked();
260 }
261 };
262 Arc::make_mut(&mut *arc)
263 }
264
265 #[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
287impl<'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
304impl<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#[derive(Debug)]
381pub struct LWeak<'a, T: ?Sized + 'static>(LWeakInner<'a, T>);
382
383#[derive(Debug)]
385enum LWeakInner<'a, T: ?Sized + 'static> {
386 Static(&'static T),
388 Local(&'a T),
390 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 #[must_use]
411 pub const fn new() -> Self {
412 LWeak(LWeakInner::Weak(Weak::new()))
413 }
414}
415
416impl<T: ?Sized> LWeak<'_, T> {
417 #[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 #[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 #[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 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}