use alloc::format;
use core::{
alloc::Layout,
cmp::Ordering,
fmt::{Debug, Display},
hash::Hash,
mem::MaybeUninit,
ops::{Deref, DerefMut},
};
use iceoryx2_bb_elementary_traits::allocator::{AllocationError, BaseAllocator};
use crate::string::*;
pub struct PolymorphicString<'a, Allocator: BaseAllocator> {
data_ptr: *mut MaybeUninit<u8>,
len: u64,
capacity: u64,
allocator: &'a Allocator,
}
impl<Allocator: BaseAllocator> internal::StringView for PolymorphicString<'_, Allocator> {
fn data(&self) -> &[MaybeUninit<u8>] {
unsafe { core::slice::from_raw_parts(self.data_ptr, self.capacity() + 1) }
}
unsafe fn data_mut(&mut self) -> &mut [MaybeUninit<u8>] {
unsafe { core::slice::from_raw_parts_mut(self.data_ptr, self.capacity() + 1) }
}
unsafe fn set_len(&mut self, len: u64) {
self.len = len;
}
}
impl<Allocator: BaseAllocator> Debug for PolymorphicString<'_, Allocator> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"PolymorphicString::<{}> {{ capacity: {}, len: {}, data: \"{}\" }}",
core::any::type_name::<Allocator>(),
self.capacity,
self.len,
as_escaped_string(self.as_bytes())
)
}
}
unsafe impl<Allocator: BaseAllocator> Send for PolymorphicString<'_, Allocator> {}
impl<Allocator: BaseAllocator> PartialOrd<PolymorphicString<'_, Allocator>>
for PolymorphicString<'_, Allocator>
{
fn partial_cmp(&self, other: &PolymorphicString<'_, Allocator>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<Allocator: BaseAllocator> Ord for PolymorphicString<'_, Allocator> {
fn cmp(&self, other: &Self) -> Ordering {
self.as_bytes().cmp(other.as_bytes())
}
}
impl<Allocator: BaseAllocator> Hash for PolymorphicString<'_, Allocator> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
state.write(self.as_bytes())
}
}
impl<Allocator: BaseAllocator> Deref for PolymorphicString<'_, Allocator> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_bytes()
}
}
impl<Allocator: BaseAllocator> DerefMut for PolymorphicString<'_, Allocator> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_bytes()
}
}
impl<Allocator: BaseAllocator> PartialEq<PolymorphicString<'_, Allocator>>
for PolymorphicString<'_, Allocator>
{
fn eq(&self, other: &PolymorphicString<'_, Allocator>) -> bool {
*self.as_bytes() == *other.as_bytes()
}
}
impl<Allocator: BaseAllocator> Eq for PolymorphicString<'_, Allocator> {}
impl<Allocator: BaseAllocator> PartialEq<&[u8]> for PolymorphicString<'_, Allocator> {
fn eq(&self, other: &&[u8]) -> bool {
*self.as_bytes() == **other
}
}
impl<Allocator: BaseAllocator> PartialEq<&str> for PolymorphicString<'_, Allocator> {
fn eq(&self, other: &&str) -> bool {
*self.as_bytes() == *other.as_bytes()
}
}
impl<Allocator: BaseAllocator> PartialEq<PolymorphicString<'_, Allocator>> for &str {
fn eq(&self, other: &PolymorphicString<'_, Allocator>) -> bool {
*self.as_bytes() == *other.as_bytes()
}
}
impl<const OTHER_CAPACITY: usize, Allocator: BaseAllocator> PartialEq<[u8; OTHER_CAPACITY]>
for PolymorphicString<'_, Allocator>
{
fn eq(&self, other: &[u8; OTHER_CAPACITY]) -> bool {
*self.as_bytes() == *other
}
}
impl<const OTHER_CAPACITY: usize, Allocator: BaseAllocator> PartialEq<&[u8; OTHER_CAPACITY]>
for PolymorphicString<'_, Allocator>
{
fn eq(&self, other: &&[u8; OTHER_CAPACITY]) -> bool {
*self.as_bytes() == **other
}
}
impl<Allocator: BaseAllocator> Display for PolymorphicString<'_, Allocator> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", as_escaped_string(self.as_bytes()))
}
}
impl<'a, Allocator: BaseAllocator> PolymorphicString<'a, Allocator> {
pub fn new(allocator: &'a Allocator, capacity: usize) -> Result<Self, AllocationError> {
let layout = Layout::array::<MaybeUninit<u8>>(capacity + 1)
.expect("Memory size for the array is smaller than isize::MAX");
let mut data_ptr = match allocator.allocate(layout) {
Ok(ptr) => ptr,
Err(e) => {
let origin = format!(
"PolymorphicString::<{}>::new(.., {})",
core::any::type_name::<Allocator>(),
capacity
);
fail!(from origin, with e,
"Failed to create new PolymorphicString due to a failure while allocating memory ({e:?}).");
}
};
Ok(Self {
data_ptr: unsafe { data_ptr.as_mut() }.as_mut_ptr().cast(),
len: 0,
capacity: capacity as _,
allocator,
})
}
pub fn try_clone(&self) -> Result<Self, AllocationError> {
let layout = Layout::array::<MaybeUninit<u8>>(self.capacity as usize + 1)
.expect("Memory size for the array is smaller than isize::MAX");
let mut data_ptr = match self.allocator.allocate(layout) {
Ok(ptr) => ptr,
Err(e) => {
let origin = format!(
"PolymorphicString::<{}>::try_clone()",
core::any::type_name::<Allocator>(),
);
fail!(from origin, with e,
"Failed to clone PolymorphicString due to a failure while allocating memory ({e:?}).");
}
};
let mut new_self = Self {
data_ptr: unsafe { data_ptr.as_mut() }.as_mut_ptr().cast(),
len: 0,
capacity: self.capacity,
allocator: self.allocator,
};
unsafe { new_self.insert_bytes_unchecked(0, self.as_bytes()) };
Ok(new_self)
}
}
impl<Allocator: BaseAllocator> String for PolymorphicString<'_, Allocator> {
fn capacity(&self) -> usize {
self.capacity as usize
}
fn len(&self) -> usize {
self.len as usize
}
}