atomicow/
lib.rs

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