extern crate alloc;
use crate::{
core::{
alloc::{NSTDAllocError, NSTDAllocator},
def::NSTDByte,
optional::NSTDOptional,
slice::{nstd_core_slice_new_unchecked, NSTDSlice},
str::{
nstd_core_str_as_bytes, nstd_core_str_from_bytes_unchecked, nstd_core_str_len,
nstd_core_str_mut_from_bytes_unchecked, NSTDStr, NSTDStrMut,
},
unichar::{NSTDOptionalUnichar, NSTDUnichar},
},
vec::{
nstd_vec_allocator, nstd_vec_as_ptr, nstd_vec_as_slice, nstd_vec_as_slice_mut,
nstd_vec_cap, nstd_vec_clear, nstd_vec_clone, nstd_vec_extend, nstd_vec_from_slice,
nstd_vec_len, nstd_vec_new, nstd_vec_new_with_cap, nstd_vec_truncate, NSTDVec,
},
NSTDFloat32, NSTDFloat64, NSTDInt, NSTDInt16, NSTDInt32, NSTDInt64, NSTDInt8, NSTDUInt,
NSTDUInt16, NSTDUInt32, NSTDUInt64, NSTDUInt8,
};
use alloc::string::{String, ToString};
use nstdapi::nstdapi;
macro_rules! gen_from_primitive {
(
$(#[$meta:meta])*
$name: ident, $FromT: ty
) => {
$(#[$meta])*
#[inline]
#[nstdapi]
pub fn $name(v: $FromT) -> NSTDString<'static> {
NSTDString::from_string(v.to_string())
}
};
}
#[nstdapi]
pub struct NSTDString<'a> {
bytes: NSTDVec<'a>,
}
impl<'a> NSTDString<'a> {
#[inline]
pub(crate) fn from_string(string: String) -> NSTDString<'a> {
NSTDString {
bytes: NSTDVec::from_vec(string.into_bytes()),
}
}
#[inline]
#[allow(dead_code)]
pub(crate) unsafe fn as_mut_vec(&mut self) -> &mut NSTDVec<'a> {
&mut self.bytes
}
}
pub type NSTDOptionalString<'a> = NSTDOptional<NSTDString<'a>>;
#[inline]
#[nstdapi]
pub const fn nstd_string_new(allocator: &NSTDAllocator) -> NSTDString<'_> {
NSTDString {
bytes: nstd_vec_new(allocator, 1, 1),
}
}
#[inline]
#[nstdapi]
pub fn nstd_string_new_with_cap(
allocator: &NSTDAllocator,
cap: NSTDUInt,
) -> NSTDOptionalString<'_> {
match nstd_vec_new_with_cap(allocator, 1, 1, cap) {
NSTDOptional::Some(bytes) => NSTDOptional::Some(NSTDString { bytes }),
NSTDOptional::None => NSTDOptional::None,
}
}
#[inline]
#[nstdapi]
pub unsafe fn nstd_string_from_str<'a>(
allocator: &'a NSTDAllocator,
str: &NSTDStr,
) -> NSTDOptionalString<'a> {
let bytes = nstd_core_str_as_bytes(str);
match nstd_vec_from_slice(allocator, &bytes) {
NSTDOptional::Some(bytes) => NSTDOptional::Some(NSTDString { bytes }),
NSTDOptional::None => NSTDOptional::None,
}
}
#[inline]
#[nstdapi]
pub fn nstd_string_from_bytes(bytes: NSTDVec<'_>) -> NSTDOptionalString<'_> {
match core::str::from_utf8(unsafe { bytes.as_slice() }).is_ok() {
true => NSTDOptional::Some(NSTDString { bytes }),
false => NSTDOptional::None,
}
}
#[inline]
#[nstdapi]
pub fn nstd_string_clone<'a>(string: &NSTDString<'a>) -> NSTDOptionalString<'a> {
match nstd_vec_clone(&string.bytes) {
NSTDOptional::Some(bytes) => NSTDOptional::Some(NSTDString { bytes }),
NSTDOptional::None => NSTDOptional::None,
}
}
#[inline]
#[nstdapi]
pub const fn nstd_string_allocator<'a>(string: &NSTDString<'a>) -> &'a NSTDAllocator {
nstd_vec_allocator(&string.bytes)
}
#[inline]
#[nstdapi]
pub const fn nstd_string_as_str(string: &NSTDString<'_>) -> NSTDStr {
let bytes = nstd_vec_as_slice(&string.bytes);
unsafe { nstd_core_str_from_bytes_unchecked(&bytes) }
}
#[inline]
#[nstdapi]
pub fn nstd_string_as_str_mut(string: &mut NSTDString<'_>) -> NSTDStrMut {
let mut bytes = nstd_vec_as_slice_mut(&mut string.bytes);
unsafe { nstd_core_str_mut_from_bytes_unchecked(&mut bytes) }
}
#[inline]
#[nstdapi]
pub const fn nstd_string_as_bytes(string: &NSTDString<'_>) -> NSTDSlice {
nstd_vec_as_slice(&string.bytes)
}
#[inline]
#[nstdapi]
pub const fn nstd_string_as_ptr(string: &NSTDString<'_>) -> *const NSTDByte {
nstd_vec_as_ptr(&string.bytes).cast()
}
#[inline]
#[nstdapi]
#[allow(clippy::missing_const_for_fn)]
pub fn nstd_string_into_bytes(string: NSTDString<'_>) -> NSTDVec<'_> {
string.bytes
}
#[inline]
#[nstdapi]
pub fn nstd_string_len(string: &NSTDString<'_>) -> NSTDUInt {
let str = nstd_string_as_str(string);
unsafe { nstd_core_str_len(&str) }
}
#[inline]
#[nstdapi]
pub const fn nstd_string_byte_len(string: &NSTDString<'_>) -> NSTDUInt {
nstd_vec_len(&string.bytes)
}
#[inline]
#[nstdapi]
pub const fn nstd_string_cap(string: &NSTDString<'_>) -> NSTDUInt {
nstd_vec_cap(&string.bytes)
}
#[nstdapi]
pub fn nstd_string_push(string: &mut NSTDString<'_>, chr: NSTDUnichar) -> NSTDAllocError {
let chr = char::from(chr);
let mut buf = [0; 4];
chr.encode_utf8(&mut buf);
unsafe {
let buf = nstd_core_slice_new_unchecked(buf.as_ptr().cast(), 1, 1, chr.len_utf8());
nstd_vec_extend(&mut string.bytes, &buf)
}
}
#[inline]
#[nstdapi]
pub unsafe fn nstd_string_push_str(string: &mut NSTDString<'_>, str: &NSTDStr) -> NSTDAllocError {
let str_bytes = nstd_core_str_as_bytes(str);
nstd_vec_extend(&mut string.bytes, &str_bytes)
}
#[nstdapi]
pub fn nstd_string_pop(string: &mut NSTDString<'_>) -> NSTDOptionalUnichar {
let str = unsafe { core::str::from_utf8_unchecked(string.bytes.as_slice()) };
if let Some(chr) = str.chars().last() {
#[allow(clippy::arithmetic_side_effects)]
let len = nstd_vec_len(&string.bytes) - chr.len_utf8();
nstd_vec_truncate(&mut string.bytes, len);
return NSTDOptional::Some(chr.into());
}
NSTDOptional::None
}
#[inline]
#[nstdapi]
pub fn nstd_string_clear(string: &mut NSTDString<'_>) {
nstd_vec_clear(&mut string.bytes);
}
gen_from_primitive!(
nstd_string_from_f32,
NSTDFloat32
);
gen_from_primitive!(
nstd_string_from_f64,
NSTDFloat64
);
gen_from_primitive!(
nstd_string_from_int,
NSTDInt
);
gen_from_primitive!(
nstd_string_from_uint,
NSTDUInt
);
gen_from_primitive!(
nstd_string_from_i8,
NSTDInt8
);
gen_from_primitive!(
nstd_string_from_u8,
NSTDUInt8
);
gen_from_primitive!(
nstd_string_from_i16,
NSTDInt16
);
gen_from_primitive!(
nstd_string_from_u16,
NSTDUInt16
);
gen_from_primitive!(
nstd_string_from_i32,
NSTDInt32
);
gen_from_primitive!(
nstd_string_from_u32,
NSTDUInt32
);
gen_from_primitive!(
nstd_string_from_i64,
NSTDInt64
);
gen_from_primitive!(
nstd_string_from_u64,
NSTDUInt64
);
#[inline]
#[nstdapi]
#[allow(
unused_variables,
clippy::missing_const_for_fn,
clippy::needless_pass_by_value
)]
pub fn nstd_string_free(string: NSTDString<'_>) {}