iceoryx2_bb_container/string/
relocatable_string.rs1use core::alloc::Layout;
70use core::cmp::Ordering;
71use core::fmt::{Debug, Display};
72use core::hash::Hash;
73use core::mem::MaybeUninit;
74use core::ops::{Deref, DerefMut};
75use iceoryx2_bb_elementary::math::unaligned_mem_size;
76use iceoryx2_bb_elementary::relocatable_ptr::RelocatablePointer;
77use iceoryx2_bb_elementary_traits::pointer_trait::PointerTrait;
78pub use iceoryx2_bb_elementary_traits::relocatable_container::RelocatableContainer;
79use iceoryx2_log::{fail, fatal_panic};
80
81use crate::string::{as_escaped_string, internal, String};
82
83#[repr(C)]
85pub struct RelocatableString {
86 data_ptr: RelocatablePointer<MaybeUninit<u8>>,
87 capacity: u64,
88 len: u64,
89}
90
91impl internal::StringView for RelocatableString {
92 fn data(&self) -> &[MaybeUninit<u8>] {
93 self.verify_init("data()");
94 unsafe { core::slice::from_raw_parts(self.data_ptr.as_ptr(), self.capacity() + 1) }
95 }
96
97 unsafe fn data_mut(&mut self) -> &mut [MaybeUninit<u8>] {
98 self.verify_init("data_mut()");
99 core::slice::from_raw_parts_mut(self.data_ptr.as_mut_ptr(), self.capacity() + 1)
100 }
101
102 unsafe fn set_len(&mut self, len: u64) {
103 self.len = len;
104 }
105}
106
107impl Debug for RelocatableString {
108 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
109 write!(
110 f,
111 "RelocatableString {{ capacity: {}, len: {}, data: \"{}\" }}",
112 self.capacity,
113 self.len,
114 as_escaped_string(self.as_bytes())
115 )
116 }
117}
118
119unsafe impl Send for RelocatableString {}
120
121impl PartialOrd<RelocatableString> for RelocatableString {
122 fn partial_cmp(&self, other: &RelocatableString) -> Option<Ordering> {
123 Some(self.cmp(other))
124 }
125}
126
127impl Ord for RelocatableString {
128 fn cmp(&self, other: &Self) -> Ordering {
129 self.as_bytes().cmp(other.as_bytes())
130 }
131}
132
133impl Hash for RelocatableString {
134 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
135 state.write(self.as_bytes())
136 }
137}
138
139impl Deref for RelocatableString {
140 type Target = [u8];
141
142 fn deref(&self) -> &Self::Target {
143 self.as_bytes()
144 }
145}
146
147impl DerefMut for RelocatableString {
148 fn deref_mut(&mut self) -> &mut Self::Target {
149 self.as_mut_bytes()
150 }
151}
152
153impl PartialEq<RelocatableString> for RelocatableString {
154 fn eq(&self, other: &RelocatableString) -> bool {
155 *self.as_bytes() == *other.as_bytes()
156 }
157}
158
159impl Eq for RelocatableString {}
160
161impl PartialEq<&[u8]> for RelocatableString {
162 fn eq(&self, other: &&[u8]) -> bool {
163 *self.as_bytes() == **other
164 }
165}
166
167impl PartialEq<&str> for RelocatableString {
168 fn eq(&self, other: &&str) -> bool {
169 *self.as_bytes() == *other.as_bytes()
170 }
171}
172
173impl PartialEq<RelocatableString> for &str {
174 fn eq(&self, other: &RelocatableString) -> bool {
175 *self.as_bytes() == *other.as_bytes()
176 }
177}
178
179impl<const OTHER_CAPACITY: usize> PartialEq<[u8; OTHER_CAPACITY]> for RelocatableString {
180 fn eq(&self, other: &[u8; OTHER_CAPACITY]) -> bool {
181 *self.as_bytes() == *other
182 }
183}
184
185impl<const OTHER_CAPACITY: usize> PartialEq<&[u8; OTHER_CAPACITY]> for RelocatableString {
186 fn eq(&self, other: &&[u8; OTHER_CAPACITY]) -> bool {
187 *self.as_bytes() == **other
188 }
189}
190
191impl Display for RelocatableString {
192 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
193 write!(f, "{}", as_escaped_string(self.as_bytes()))
194 }
195}
196
197impl RelocatableString {
198 #[inline(always)]
199 fn verify_init(&self, source: &str) {
200 debug_assert!(
201 self.data_ptr.is_initialized(),
202 "From: RelocatableString::{}, Undefined behavior - the object was not initialized with 'init' before.",
203 source
204 );
205 }
206
207 pub const fn const_memory_size(capacity: usize) -> usize {
209 unaligned_mem_size::<u8>(capacity + 1)
210 }
211}
212
213impl RelocatableContainer for RelocatableString {
214 unsafe fn new_uninit(capacity: usize) -> Self {
215 Self {
216 data_ptr: RelocatablePointer::new_uninit(),
217 capacity: capacity as u64,
218 len: 0,
219 }
220 }
221
222 unsafe fn init<Allocator: iceoryx2_bb_elementary_traits::allocator::BaseAllocator>(
223 &mut self,
224 allocator: &Allocator,
225 ) -> Result<(), iceoryx2_bb_elementary_traits::allocator::AllocationError> {
226 let origin = "RelocatableString::init()";
227 if self.data_ptr.is_initialized() {
228 fatal_panic!(from origin,
229 "Memory already initialized! Initializing it twice may lead to undefined behavior.");
230 }
231
232 let ptr = match allocator.allocate(Layout::from_size_align_unchecked(
233 core::mem::size_of::<u8>() * (self.capacity as usize + 1),
234 core::mem::align_of::<u8>(),
235 )) {
236 Ok(ptr) => ptr,
237 Err(e) => {
238 fail!(from origin, with e,
239 "Failed to initialize since the allocation of the data memory failed.");
240 }
241 };
242
243 self.data_ptr.init(ptr);
244
245 Ok(())
246 }
247
248 fn memory_size(capacity: usize) -> usize {
249 Self::const_memory_size(capacity)
250 }
251}
252
253impl String for RelocatableString {
254 fn capacity(&self) -> usize {
255 self.capacity as usize
256 }
257
258 fn len(&self) -> usize {
259 self.len as usize
260 }
261}