osom_lib_strings/
immutable_string.rs1use core::mem::ManuallyDrop;
4
5use osom_lib_alloc::Allocator;
6use osom_lib_arrays::{ImmutableArray, ImmutableWeakArray, errors::ArrayConstructionError};
7use osom_lib_primitives::Length;
8
9#[cfg(feature = "std_alloc")]
10use osom_lib_alloc::StdAllocator;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14#[must_use]
15#[repr(u8)]
16pub enum ImmutableStringConstructionError {
17 AllocationError,
19
20 StringTooLong,
22}
23
24impl From<ArrayConstructionError> for ImmutableStringConstructionError {
25 fn from(error: ArrayConstructionError) -> Self {
26 match error {
27 ArrayConstructionError::AllocationError => ImmutableStringConstructionError::AllocationError,
28 ArrayConstructionError::ArrayTooLong => ImmutableStringConstructionError::StringTooLong,
29 }
30 }
31}
32
33#[derive(Clone)]
46#[repr(transparent)]
47#[must_use]
48pub struct ImmutableString<
49 #[cfg(feature = "std_alloc")] TAllocator = StdAllocator,
50 #[cfg(not(feature = "std_alloc"))] TAllocator,
51> where
52 TAllocator: Allocator,
53{
54 internal: ManuallyDrop<ImmutableArray<u8, TAllocator>>,
55}
56
57unsafe impl<TAllocator: Allocator> Send for ImmutableString<TAllocator> {}
58unsafe impl<TAllocator: Allocator> Sync for ImmutableString<TAllocator> {}
59
60#[derive(Clone)]
64#[repr(transparent)]
65pub struct ImmutableWeakString<
66 #[cfg(feature = "std_alloc")] TAllocator = StdAllocator,
67 #[cfg(not(feature = "std_alloc"))] TAllocator,
68> where
69 TAllocator: Allocator,
70{
71 internal: ManuallyDrop<ImmutableWeakArray<u8, TAllocator>>,
72}
73
74impl<TAllocator: Allocator> ImmutableWeakString<TAllocator> {
75 fn from_internal(internal: ImmutableWeakArray<u8, TAllocator>) -> Self {
76 Self {
77 internal: ManuallyDrop::new(internal),
78 }
79 }
80
81 #[inline(always)]
87 pub fn upgrade(&self) -> Option<ImmutableString<TAllocator>> {
88 let internal = self.internal.upgrade()?;
89 Some(ImmutableString::from_internal(internal))
90 }
91
92 #[inline(always)]
94 #[must_use]
95 pub fn strong_count(instance: &Self) -> usize {
96 instance.internal.strong_count()
97 }
98
99 #[inline(always)]
101 #[must_use]
102 pub fn weak_count(instance: &Self) -> usize {
103 instance.internal.weak_count()
104 }
105
106 #[inline(always)]
110 pub fn release(mut self) -> bool {
111 let internal = unsafe { ManuallyDrop::take(&mut self.internal) };
112 let val = internal.release();
113 core::mem::forget(self);
114 val
115 }
116}
117
118impl<TAllocator: Allocator> Drop for ImmutableWeakString<TAllocator> {
119 fn drop(&mut self) {
120 unsafe { ManuallyDrop::drop(&mut self.internal) };
121 }
122}
123
124impl<TAllocator: Allocator> ImmutableString<TAllocator> {
125 fn from_internal(internal: ImmutableArray<u8, TAllocator>) -> Self {
126 Self {
127 internal: ManuallyDrop::new(internal),
128 }
129 }
130
131 pub const MAX_LENGTH: usize = ImmutableArray::<u8, TAllocator>::MAX_LENGTH;
132
133 pub fn new(text: &str) -> Result<Self, ImmutableStringConstructionError> {
140 Self::with_allocator(text, TAllocator::default())
141 }
142
143 pub fn with_allocator(text: &str, allocator: TAllocator) -> Result<Self, ImmutableStringConstructionError> {
150 let array = ImmutableArray::from_slice_with_allocator(text.as_bytes(), allocator)?;
151 Ok(Self {
152 internal: ManuallyDrop::new(array),
153 })
154 }
155
156 #[inline(always)]
157 #[must_use]
158 pub fn as_str(&self) -> &str {
159 let slice = self.internal.as_slice();
160 unsafe { core::str::from_utf8_unchecked(slice) }
161 }
162
163 #[inline(always)]
165 pub fn downgrade(instance: &Self) -> ImmutableWeakString<TAllocator> {
166 ImmutableWeakString::from_internal(ImmutableArray::downgrade(&instance.internal))
167 }
168
169 #[inline(always)]
171 #[must_use]
172 pub fn strong_count(instance: &Self) -> usize {
173 ImmutableArray::strong_count(&instance.internal)
174 }
175
176 #[inline(always)]
178 #[must_use]
179 pub fn weak_count(instance: &Self) -> usize {
180 ImmutableArray::weak_count(&instance.internal)
181 }
182
183 #[inline(always)]
185 pub fn len(&self) -> Length {
186 self.internal.len()
187 }
188
189 #[inline(always)]
191 #[must_use]
192 pub fn is_empty(&self) -> bool {
193 self.len().value() == 0
194 }
195
196 pub fn release(mut instance: Self) -> Option<ImmutableWeakString<TAllocator>> {
199 let internal = unsafe { ManuallyDrop::take(&mut instance.internal) };
200 let weak = ImmutableArray::release(internal)?;
201 core::mem::forget(instance);
202 Some(ImmutableWeakString::from_internal(weak))
203 }
204
205 #[inline(always)]
211 pub unsafe fn from_unchecked(value: ImmutableArray<u8, TAllocator>) -> Self {
212 Self {
213 internal: ManuallyDrop::new(value),
214 }
215 }
216}
217
218impl<TAllocator: Allocator> Drop for ImmutableString<TAllocator> {
219 fn drop(&mut self) {
220 unsafe { ManuallyDrop::drop(&mut self.internal) };
221 }
222}
223
224impl<TAllocator: Allocator> core::ops::Deref for ImmutableString<TAllocator> {
225 type Target = str;
226
227 fn deref(&self) -> &Self::Target {
228 self.as_str()
229 }
230}
231
232impl<TAllocator: Allocator> core::fmt::Debug for ImmutableString<TAllocator> {
233 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
234 f.debug_struct("ImmutableWeakString")
235 .field("strong_count", &Self::strong_count(self))
236 .field("weak_count", &Self::weak_count(self))
237 .field("len", &self.len())
238 .field("capacity", &self.internal.capacity())
239 .finish()
240 }
241}
242
243impl<TAllocator1: Allocator, TAllocator2: Allocator> core::cmp::PartialEq<ImmutableString<TAllocator1>>
244 for ImmutableString<TAllocator2>
245{
246 fn eq(&self, other: &ImmutableString<TAllocator1>) -> bool {
247 self.as_str() == other.as_str()
248 }
249}
250
251impl<TAllocator: Allocator> core::cmp::Eq for ImmutableString<TAllocator> {}
252
253impl<TAllocator: Allocator> core::hash::Hash for ImmutableString<TAllocator> {
254 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
255 self.internal.hash(state);
256 }
257}
258
259impl<TAllocator: Allocator> TryFrom<ImmutableArray<u8, TAllocator>> for ImmutableString<TAllocator> {
260 type Error = core::str::Utf8Error;
261
262 fn try_from(value: ImmutableArray<u8, TAllocator>) -> Result<Self, Self::Error> {
263 let _ = core::str::from_utf8(value.as_slice())?;
264 Ok(Self {
265 internal: ManuallyDrop::new(value),
266 })
267 }
268}
269
270impl<TAllocator: Allocator> From<ImmutableString<TAllocator>> for ImmutableArray<u8, TAllocator> {
271 fn from(mut value: ImmutableString<TAllocator>) -> Self {
272 let internal = unsafe { ManuallyDrop::take(&mut value.internal) };
273 core::mem::forget(value);
274 internal
275 }
276}