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