atomicow/
lib.rs

1//! <style>
2//! .rustdoc-hidden { display: none; }
3//! </style>
4#![doc = include_str!("../README.md")]
5#![no_std]
6
7extern crate alloc;
8
9#[cfg(feature = "std")]
10extern crate std;
11
12use alloc::string::String;
13use core::{
14    borrow::Borrow,
15    fmt::{Debug, Display},
16    hash::Hash,
17    ops::Deref,
18};
19
20#[cfg(feature = "std")]
21use std::path::{Path, PathBuf};
22
23#[cfg(target_has_atomic = "ptr")]
24use alloc::sync::Arc;
25
26#[cfg(not(target_has_atomic = "ptr"))]
27use portable_atomic_util::Arc;
28
29/// Much like a [`Cow`](std::borrow::Cow), but owned values are [`Arc`]-ed to make clones cheap.
30/// This should be used for values that are cloned for use across threads and change rarely (if
31/// ever).
32///
33/// This also makes an opinionated tradeoff by adding a [`CowArc::Static`] and implementing
34/// `From<&'static T>` instead of `From<'a T>`. This preserves the static context and prevents
35/// conversion to [`CowArc::Owned`] in cases where a reference is known to be static. This is an
36/// optimization that prevents allocations and atomic ref-counting.
37///
38/// This means that static references should prefer [`CowArc::from`] or [`CowArc::Static`] and
39/// non-static references must use [`CowArc::Borrowed`].
40pub enum CowArc<'a, T: ?Sized + 'static> {
41    /// A borrowed value.
42    Borrowed(&'a T),
43    /// A static value reference.
44    ///
45    /// This exists to avoid conversion to [`CowArc::Owned`] in cases where a reference is
46    /// known to be static. This is an optimization that prevents allocations and atomic
47    /// ref-counting.
48    Static(&'static T),
49    /// An owned [`Arc`]-ed value.
50    Owned(Arc<T>),
51}
52
53impl<T: ?Sized + 'static> CowArc<'static, T> {
54    /// Creates a new [`CowArc::Owned`] from a value.
55    ///
56    /// This is simply a convenience method;
57    /// the value will be wrapped in an [`Arc`].
58    ///
59    /// Note that `T` must be [`Sized`]: use the enum constructor directly if `T` is unsized.
60    pub fn new_owned(value: T) -> Self
61    where
62        T: Sized,
63    {
64        CowArc::Owned(Arc::new(value))
65    }
66
67    /// Creates a new [`CowArc::Owned`] from an [`Arc`]-like value.
68    ///
69    /// The [`Arc`] will be moved into the [`CowArc`].
70    pub fn new_owned_from_arc(value: impl Into<Arc<T>>) -> Self {
71        CowArc::Owned(value.into())
72    }
73}
74
75impl<T: ?Sized> CowArc<'static, T> {
76    /// Indicates this [`CowArc`] should have a static lifetime.
77    ///
78    /// This ensures if this was created with a value `Borrowed(&'static T)`, it is replaced with
79    /// `Static(&'static T)`. It is only possible to call this method if `'a` is `'static`.
80    /// This has no effect if this is `Owned(Arc<T>)`.
81    #[inline]
82    pub fn as_static(self) -> Self {
83        match self {
84            Self::Borrowed(value) | Self::Static(value) => Self::Static(value),
85            Self::Owned(value) => Self::Owned(value),
86        }
87    }
88}
89
90impl<T: ?Sized> Deref for CowArc<'_, T> {
91    type Target = T;
92
93    #[inline]
94    fn deref(&self) -> &Self::Target {
95        match self {
96            CowArc::Borrowed(v) | CowArc::Static(v) => v,
97            CowArc::Owned(v) => v,
98        }
99    }
100}
101
102impl<T: ?Sized> Borrow<T> for CowArc<'_, T> {
103    #[inline]
104    fn borrow(&self) -> &T {
105        self
106    }
107}
108
109impl<T: ?Sized> AsRef<T> for CowArc<'_, T> {
110    #[inline]
111    fn as_ref(&self) -> &T {
112        self
113    }
114}
115
116impl<'a, T: ?Sized> CowArc<'a, T>
117where
118    &'a T: Into<Arc<T>>,
119{
120    /// Converts this into an "owned" value.
121    ///
122    /// If internally a value is borrowed, it will be cloned into an "owned [`Arc`]".
123    /// If it is already a [`CowArc::Owned`] or a [`CowArc::Static`], it will remain unchanged.
124    #[inline]
125    pub fn into_owned(self) -> CowArc<'static, T> {
126        match self {
127            CowArc::Borrowed(value) => CowArc::Owned(value.into()),
128            CowArc::Static(value) => CowArc::Static(value),
129            CowArc::Owned(value) => CowArc::Owned(value),
130        }
131    }
132
133    /// Clones into an owned [`CowArc<'static>`].
134    ///
135    /// If internally a value is borrowed, it will be cloned into an "owned [`Arc`]".
136    /// If it is already a [`CowArc::Owned`] or [`CowArc::Static`], the value will be cloned.
137    /// This is equivalent to `.clone().into_owned()`.
138    #[inline]
139    pub fn clone_owned(&self) -> CowArc<'static, T> {
140        self.clone().into_owned()
141    }
142}
143
144impl<T: ?Sized> Clone for CowArc<'_, T> {
145    #[inline]
146    fn clone(&self) -> Self {
147        match self {
148            Self::Borrowed(value) => Self::Borrowed(value),
149            Self::Static(value) => Self::Static(value),
150            Self::Owned(value) => Self::Owned(value.clone()),
151        }
152    }
153}
154
155impl<T: PartialEq + ?Sized> PartialEq for CowArc<'_, T> {
156    #[inline]
157    fn eq(&self, other: &Self) -> bool {
158        self.deref().eq(other.deref())
159    }
160}
161
162impl<T: PartialEq + ?Sized> Eq for CowArc<'_, T> {}
163
164impl<T: Hash + ?Sized> Hash for CowArc<'_, T> {
165    #[inline]
166    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
167        self.deref().hash(state);
168    }
169}
170
171impl<T: Debug + ?Sized> Debug for CowArc<'_, T> {
172    #[inline]
173    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174        Debug::fmt(self.deref(), f)
175    }
176}
177
178impl<T: Display + ?Sized> Display for CowArc<'_, T> {
179    #[inline]
180    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
181        Display::fmt(self.deref(), f)
182    }
183}
184
185impl<T: PartialOrd + ?Sized> PartialOrd for CowArc<'_, T> {
186    #[inline]
187    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
188        self.deref().partial_cmp(other.deref())
189    }
190}
191
192impl Default for CowArc<'static, str> {
193    fn default() -> Self {
194        CowArc::Static(Default::default())
195    }
196}
197
198#[cfg(feature = "std")]
199// A shortcut, since `Path` does not implement `Default`.
200impl Default for CowArc<'static, Path> {
201    /// Returns an empty [`Path`], wrapped in [`CowArc::Static`].
202    ///
203    /// This is equivalent to `CowArc::Static(Path::new(""))`.
204    fn default() -> Self {
205        CowArc::Static(Path::new(""))
206    }
207}
208
209impl<T: Ord + ?Sized> Ord for CowArc<'_, T> {
210    #[inline]
211    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
212        self.deref().cmp(other.deref())
213    }
214}
215
216#[cfg(feature = "std")]
217impl From<PathBuf> for CowArc<'static, Path> {
218    #[inline]
219    fn from(value: PathBuf) -> Self {
220        CowArc::Owned(value.into())
221    }
222}
223
224#[cfg(feature = "std")]
225impl From<&'static str> for CowArc<'static, Path> {
226    #[inline]
227    fn from(value: &'static str) -> Self {
228        CowArc::Static(Path::new(value))
229    }
230}
231
232impl From<String> for CowArc<'static, str> {
233    #[inline]
234    fn from(value: String) -> Self {
235        CowArc::Owned(value.into())
236    }
237}
238
239impl<'a> From<&'a String> for CowArc<'a, str> {
240    #[inline]
241    fn from(value: &'a String) -> Self {
242        CowArc::Borrowed(value)
243    }
244}
245
246impl<T: ?Sized> From<&'static T> for CowArc<'static, T> {
247    #[inline]
248    fn from(value: &'static T) -> Self {
249        CowArc::Static(value)
250    }
251}
252
253impl<T> From<Arc<T>> for CowArc<'static, T> {
254    #[inline]
255    fn from(value: Arc<T>) -> Self {
256        CowArc::Owned(value)
257    }
258}