|
1 | 1 | use std::fmt;
|
2 |
| -use std::sync::atomic::{AtomicPtr, Ordering}; |
3 |
| -use std::sync::Arc; |
| 2 | +use std::ops::Deref; |
| 3 | + |
| 4 | +use arc_swap::{ArcSwapAny, Guard}; |
| 5 | +use triomphe::Arc; |
4 | 6 |
|
5 | 7 | /// A thread-safe atomically reference-counting string.
|
6 |
| -pub struct AtomicStr(AtomicPtr<String>); |
| 8 | +pub struct AtomicStr(ArcSwapAny<Arc<String>>); |
| 9 | + |
| 10 | +/// A thread-safe view the string that was stored when `AtomicStr::as_str()` was called. |
| 11 | +struct GuardedStr(Guard<Arc<String>>); |
| 12 | + |
| 13 | +impl Deref for GuardedStr { |
| 14 | + type Target = str; |
| 15 | + |
| 16 | + fn deref(&self) -> &Self::Target { |
| 17 | + self.0.as_str() |
| 18 | + } |
| 19 | +} |
7 | 20 |
|
8 | 21 | impl AtomicStr {
|
9 | 22 | /// Create a new `AtomicStr` with the given value.
|
10 |
| - pub fn new(value: impl Into<String>) -> Self { |
| 23 | + pub fn new(value: &str) -> Self { |
11 | 24 | let arced = Arc::new(value.into());
|
12 |
| - Self(AtomicPtr::new(Arc::into_raw(arced) as _)) |
| 25 | + Self(ArcSwapAny::new(arced)) |
13 | 26 | }
|
14 | 27 |
|
15 | 28 | /// Get the string slice.
|
16 |
| - pub fn as_str(&self) -> &str { |
17 |
| - unsafe { |
18 |
| - let arced_ptr = self.0.load(Ordering::SeqCst); |
19 |
| - assert!(!arced_ptr.is_null()); |
20 |
| - &*arced_ptr |
21 |
| - } |
22 |
| - } |
23 |
| - |
24 |
| - /// Get the cloned inner `Arc<String>`. |
25 |
| - pub fn clone_string(&self) -> Arc<String> { |
26 |
| - unsafe { |
27 |
| - let arced_ptr = self.0.load(Ordering::SeqCst); |
28 |
| - assert!(!arced_ptr.is_null()); |
29 |
| - Arc::increment_strong_count(arced_ptr); |
30 |
| - Arc::from_raw(arced_ptr) |
31 |
| - } |
| 29 | + pub fn as_str(&self) -> impl Deref<Target = str> { |
| 30 | + GuardedStr(self.0.load()) |
32 | 31 | }
|
33 | 32 |
|
34 |
| - /// Replaces the value at self with src, returning the old value, without dropping either. |
35 |
| - pub fn replace(&self, src: impl Into<String>) -> Arc<String> { |
36 |
| - unsafe { |
37 |
| - let arced_new = Arc::new(src.into()); |
38 |
| - let arced_old_ptr = self.0.swap(Arc::into_raw(arced_new) as _, Ordering::SeqCst); |
39 |
| - assert!(!arced_old_ptr.is_null()); |
40 |
| - Arc::from_raw(arced_old_ptr) |
41 |
| - } |
| 33 | + /// Replaces the value at self with src. |
| 34 | + pub fn replace(&self, src: impl Into<String>) { |
| 35 | + let arced = Arc::new(src.into()); |
| 36 | + self.0.store(arced); |
42 | 37 | }
|
43 | 38 | }
|
44 | 39 |
|
45 |
| -impl Drop for AtomicStr { |
46 |
| - fn drop(&mut self) { |
47 |
| - unsafe { |
48 |
| - let arced_ptr = self.0.swap(std::ptr::null_mut(), Ordering::SeqCst); |
49 |
| - assert!(!arced_ptr.is_null()); |
50 |
| - let _ = Arc::from_raw(arced_ptr); |
51 |
| - } |
| 40 | +impl From<&str> for AtomicStr { |
| 41 | + fn from(value: &str) -> Self { |
| 42 | + Self::new(value) |
52 | 43 | }
|
53 | 44 | }
|
54 | 45 |
|
55 |
| -impl AsRef<str> for AtomicStr { |
56 |
| - fn as_ref(&self) -> &str { |
57 |
| - self.as_str() |
| 46 | +impl fmt::Display for AtomicStr { |
| 47 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 48 | + f.write_str(&self.as_str()) |
58 | 49 | }
|
59 | 50 | }
|
60 | 51 |
|
61 |
| -impl<T> From<T> for AtomicStr |
62 |
| -where |
63 |
| - T: Into<String>, |
64 |
| -{ |
65 |
| - fn from(value: T) -> Self { |
66 |
| - Self::new(value) |
67 |
| - } |
68 |
| -} |
| 52 | +#[cfg(test)] |
| 53 | +mod tests { |
| 54 | + use super::*; |
69 | 55 |
|
70 |
| -impl From<&AtomicStr> for Arc<String> { |
71 |
| - fn from(value: &AtomicStr) -> Self { |
72 |
| - value.clone_string() |
| 56 | + fn test_str(s: &str) { |
| 57 | + assert_eq!(s, "hello"); |
73 | 58 | }
|
74 |
| -} |
75 | 59 |
|
76 |
| -impl fmt::Display for AtomicStr { |
77 |
| - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
78 |
| - write!(f, "{}", self.as_str()) |
| 60 | + #[test] |
| 61 | + fn test_atomic_str() { |
| 62 | + let s = AtomicStr::from("hello"); |
| 63 | + test_str(&s.as_str()); |
79 | 64 | }
|
80 | 65 | }
|
0 commit comments