osom_tools_runtime/
immutable_string.rs1use core::mem::ManuallyDrop;
4
5use crate::{
6 Length,
7 allocator::Allocator,
8 arrays::{ImmutableArray, ImmutableArrayConstructionError, ImmutableWeakArray},
9};
10
11#[cfg(feature = "std_alloc")]
12use crate::allocator::StdAllocator;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16#[must_use]
17#[repr(u8)]
18pub enum ImmutableStringConstructionError {
19 AllocationError,
21
22 StringTooLong,
24}
25
26impl From<ImmutableArrayConstructionError> for ImmutableStringConstructionError {
27 fn from(error: ImmutableArrayConstructionError) -> Self {
28 match error {
29 ImmutableArrayConstructionError::AllocationError => ImmutableStringConstructionError::AllocationError,
30 ImmutableArrayConstructionError::ArrayTooLong => ImmutableStringConstructionError::StringTooLong,
31 }
32 }
33}
34
35#[derive(Clone)]
48#[repr(transparent)]
49#[must_use]
50pub struct ImmutableString<
51 #[cfg(feature = "std_alloc")] TAllocator = StdAllocator,
52 #[cfg(not(feature = "std_alloc"))] TAllocator,
53> where
54 TAllocator: Allocator,
55{
56 internal: ManuallyDrop<ImmutableArray<u8, TAllocator>>,
57}
58
59unsafe impl<TAllocator: Allocator> Send for ImmutableString<TAllocator> {}
60unsafe impl<TAllocator: Allocator> Sync for ImmutableString<TAllocator> {}
61
62#[derive(Clone)]
66#[repr(transparent)]
67pub struct ImmutableWeakString<
68 #[cfg(feature = "std_alloc")] TAllocator = StdAllocator,
69 #[cfg(not(feature = "std_alloc"))] TAllocator,
70> where
71 TAllocator: Allocator,
72{
73 internal: ManuallyDrop<ImmutableWeakArray<u8, TAllocator>>,
74}
75
76impl<TAllocator: Allocator> ImmutableWeakString<TAllocator> {
77 fn from_internal(internal: ImmutableWeakArray<u8, TAllocator>) -> Self {
78 Self {
79 internal: ManuallyDrop::new(internal),
80 }
81 }
82
83 pub fn upgrade(&self) -> Option<ImmutableString<TAllocator>> {
89 let internal = self.internal.upgrade()?;
90 Some(ImmutableString::from_internal(internal))
91 }
92
93 pub fn strong_count(instance: &Self) -> usize {
95 instance.internal.strong_count()
96 }
97
98 pub fn weak_count(instance: &Self) -> usize {
100 instance.internal.weak_count()
101 }
102
103 pub fn release(mut self) -> bool {
107 self.internal.internal_release()
108 }
109}
110
111impl<TAllocator: Allocator> Drop for ImmutableWeakString<TAllocator> {
112 fn drop(&mut self) {
113 unsafe { ManuallyDrop::drop(&mut self.internal) };
114 }
115}
116
117impl<TAllocator: Allocator> ImmutableString<TAllocator> {
118 fn from_internal(internal: ImmutableArray<u8, TAllocator>) -> Self {
119 Self {
120 internal: ManuallyDrop::new(internal),
121 }
122 }
123
124 pub const MAX_LENGTH: usize = ImmutableArray::<u8, TAllocator>::MAX_LENGTH;
125
126 pub fn new(text: &str) -> Result<Self, ImmutableStringConstructionError> {
133 Self::with_allocator(text, TAllocator::default())
134 }
135
136 pub fn with_allocator(text: &str, allocator: TAllocator) -> Result<Self, ImmutableStringConstructionError> {
143 let array = ImmutableArray::from_slice_with_allocator(text.as_bytes(), allocator)?;
144 Ok(Self {
145 internal: ManuallyDrop::new(array),
146 })
147 }
148
149 pub fn as_str(&self) -> &str {
150 let slice = self.internal.as_slice();
151 unsafe { core::str::from_utf8_unchecked(slice) }
152 }
153
154 pub fn downgrade(instance: &Self) -> ImmutableWeakString<TAllocator> {
156 ImmutableWeakString::from_internal(ImmutableArray::downgrade(&instance.internal))
157 }
158
159 pub fn strong_count(instance: &Self) -> usize {
161 ImmutableArray::strong_count(&instance.internal)
162 }
163
164 pub fn weak_count(instance: &Self) -> usize {
166 ImmutableArray::weak_count(&instance.internal)
167 }
168
169 pub fn len(&self) -> Length {
171 self.internal.len()
172 }
173
174 pub fn release(mut instance: Self) -> Option<ImmutableWeakString<TAllocator>> {
177 let weak = instance.internal.internal_release()?;
178 Some(ImmutableWeakString::from_internal(weak))
179 }
180
181 #[inline(always)]
187 pub unsafe fn from_unchecked(value: ImmutableArray<u8, TAllocator>) -> Self {
188 Self {
189 internal: ManuallyDrop::new(value),
190 }
191 }
192}
193
194impl<TAllocator: Allocator> Drop for ImmutableString<TAllocator> {
195 fn drop(&mut self) {
196 unsafe { ManuallyDrop::drop(&mut self.internal) };
197 }
198}
199
200impl<TAllocator: Allocator> core::ops::Deref for ImmutableString<TAllocator> {
201 type Target = str;
202
203 fn deref(&self) -> &Self::Target {
204 self.as_str()
205 }
206}
207
208impl<TAllocator: Allocator> core::fmt::Debug for ImmutableString<TAllocator> {
209 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
210 f.debug_struct("ImmutableWeakString")
211 .field("strong_count", &Self::strong_count(self))
212 .field("weak_count", &Self::weak_count(self))
213 .field("len", &self.len())
214 .field("capacity", &self.internal.capacity())
215 .finish()
216 }
217}
218
219impl<TAllocator1: Allocator, TAllocator2: Allocator> core::cmp::PartialEq<ImmutableString<TAllocator1>>
220 for ImmutableString<TAllocator2>
221{
222 fn eq(&self, other: &ImmutableString<TAllocator1>) -> bool {
223 self.as_str() == other.as_str()
224 }
225}
226
227impl<TAllocator: Allocator> core::cmp::Eq for ImmutableString<TAllocator> {}
228
229impl<TAllocator: Allocator> core::hash::Hash for ImmutableString<TAllocator> {
230 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
231 self.internal.hash(state);
232 }
233}
234
235impl<TAllocator: Allocator> TryFrom<ImmutableArray<u8, TAllocator>> for ImmutableString<TAllocator> {
236 type Error = core::str::Utf8Error;
237
238 fn try_from(value: ImmutableArray<u8, TAllocator>) -> Result<Self, Self::Error> {
239 let _ = core::str::from_utf8(value.as_slice())?;
240 Ok(Self {
241 internal: ManuallyDrop::new(value),
242 })
243 }
244}
245
246impl<TAllocator: Allocator> From<ImmutableString<TAllocator>> for ImmutableArray<u8, TAllocator> {
247 fn from(mut value: ImmutableString<TAllocator>) -> Self {
248 let internal = unsafe { ManuallyDrop::take(&mut value.internal) };
249 core::mem::forget(value);
250 internal
251 }
252}