osom_lib_strings/immutable/
immutable_string.rs1#![allow(clippy::cast_possible_truncation)]
2
3use core::{borrow::Borrow, fmt::Display, hash::Hash};
4
5use osom_lib_alloc::traits::Allocator;
6use osom_lib_arc::carc_array::CArcArray;
7use osom_lib_primitives::length::Length;
8use osom_lib_reprc::macros::reprc;
9use osom_lib_try_clone::TryClone;
10
11use crate::immutable::{ImmutableStringError, MaxReferencesExceededError, WeakImmutableString};
12
13#[reprc]
20#[repr(transparent)]
21#[derive(Debug)]
22#[must_use]
23pub struct ImmutableString<TAllocator: Allocator> {
24 internal: CArcArray<u8, TAllocator>,
25}
26
27impl<TAllocator: Allocator> ImmutableString<TAllocator> {
28 #[inline(always)]
29 pub(crate) fn from_internal(internal: CArcArray<u8, TAllocator>) -> Self {
30 Self { internal }
31 }
32
33 #[inline(always)]
41 pub fn empty() -> Result<Self, ImmutableStringError>
42 where
43 TAllocator: Default,
44 {
45 Self::empty_with_allocator(TAllocator::default())
46 }
47
48 #[inline(always)]
57 pub fn from_str_slice(text: &str) -> Result<Self, ImmutableStringError>
58 where
59 TAllocator: Default,
60 {
61 Self::from_str_slice_and_allocator(text, TAllocator::default())
62 }
63
64 #[inline]
73 pub fn from_str_slice_and_allocator(text: &str, allocator: TAllocator) -> Result<Self, ImmutableStringError> {
74 let text_len = Length::try_from_usize(text.len())?;
75 let mut builder = super::ImmutableStringBuilder::with_capacity_and_allocator(text_len, allocator)?;
76 builder.try_push(text)?;
77 let result = builder.build()?;
78 Ok(result)
79 }
80
81 #[inline(always)]
89 pub fn empty_with_allocator(allocator: TAllocator) -> Result<Self, ImmutableStringError> {
90 Self::from_str_slice_and_allocator("", allocator)
91 }
92
93 #[inline(always)]
94 #[must_use]
95 pub fn strong_count(&self) -> u32 {
96 CArcArray::strong_count(&self.internal)
97 }
98
99 #[inline(always)]
100 #[must_use]
101 pub fn weak_count(&self) -> u32 {
102 CArcArray::weak_count(&self.internal)
103 }
104
105 #[inline]
110 #[must_use]
111 pub fn ptr_eq(&self, other: &Self) -> bool {
112 core::ptr::eq(CArcArray::data(&self.internal), CArcArray::data(&other.internal))
113 }
114
115 #[inline]
117 #[must_use]
118 pub fn as_str(&self) -> &str {
119 unsafe {
120 let slice = self.internal.as_ref();
121 core::str::from_utf8_unchecked(&slice[..slice.len() - 1])
122 }
123 }
124
125 #[inline]
131 #[must_use]
132 pub fn as_c_str(&self) -> &str {
133 unsafe {
134 let slice = self.internal.as_ref();
135 core::str::from_utf8_unchecked(slice)
136 }
137 }
138
139 #[inline]
141 pub fn length(&self) -> Length {
142 unsafe {
143 let slice = self.internal.as_ref();
144 Length::new_unchecked((slice.len() - 1) as u32)
145 }
146 }
147
148 pub fn downgrade(&self) -> Result<WeakImmutableString<TAllocator>, MaxReferencesExceededError> {
155 let weak = CArcArray::downgrade(&self.internal)?;
156 Ok(WeakImmutableString::from_internal(weak))
157 }
158
159 #[inline]
165 #[must_use]
166 pub fn abandon(self) -> Option<WeakImmutableString<TAllocator>> {
167 let result = CArcArray::<u8, TAllocator>::abandon(self.internal)?;
168 Some(WeakImmutableString::from_internal(result))
169 }
170}
171
172impl<TAllocator: Allocator> TryClone for ImmutableString<TAllocator> {
173 type Error = MaxReferencesExceededError;
174
175 fn try_clone(&self) -> Result<Self, Self::Error> {
176 let internal = self.internal.try_clone()?;
177 Ok(Self { internal })
178 }
179}
180
181impl<TAllocator: Allocator> Clone for ImmutableString<TAllocator> {
182 fn clone(&self) -> Self {
183 self.try_clone()
184 .expect("ImmutableString strong reference count is too high.")
185 }
186}
187
188impl<TAllocator: Allocator> AsRef<str> for ImmutableString<TAllocator> {
189 fn as_ref(&self) -> &str {
190 self.as_str()
191 }
192}
193
194impl<TAllocator: Allocator> Borrow<str> for ImmutableString<TAllocator> {
195 fn borrow(&self) -> &str {
196 self.as_str()
197 }
198}
199
200impl<TAllocator: Allocator> Hash for ImmutableString<TAllocator> {
201 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
202 self.as_str().hash(state);
203 }
204}
205
206impl<TAllocator: Allocator> PartialEq for ImmutableString<TAllocator> {
207 fn eq(&self, other: &Self) -> bool {
208 self.internal == other.internal
209 }
210}
211
212impl<TAllocator: Allocator> Eq for ImmutableString<TAllocator> {}
213
214impl<TAllocator: Allocator> Display for ImmutableString<TAllocator> {
215 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
216 write!(f, "{}", self.as_str())
217 }
218}