use crate::{
def::{NSTDAny, NSTDBool, NSTDChar},
range::NSTDURange,
slice::NSTDSlice,
};
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct NSTDStr {
pub bytes: NSTDSlice,
}
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_core_str_from_cstring(cstring: *const NSTDChar) -> NSTDStr {
const C_CHAR_SIZE: usize = core::mem::size_of::<NSTDChar>();
let mut size = 0;
while *cstring.add(size) != 0 {
size += 1;
}
NSTDStr {
bytes: crate::slice::nstd_core_slice_new(size, C_CHAR_SIZE, cstring as NSTDAny),
}
}
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_core_str_from_cstring_with_null(cstring: *const NSTDChar) -> NSTDStr {
let mut str = nstd_core_str_from_cstring(cstring);
str.bytes.size += 1;
str
}
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_core_str_from_bytes(slice: &NSTDSlice) -> NSTDStr {
NSTDStr {
bytes: if slice.ptr.size == 1 {
*slice
} else {
crate::slice::nstd_core_slice_new(0, 0, core::ptr::null_mut())
},
}
}
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_core_str_len(str: &NSTDStr) -> usize {
match core::str::from_utf8(str.bytes.as_byte_slice()) {
Ok(str) => str.chars().count(),
_ => usize::MAX,
}
}
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_core_str_byte_len(str: &NSTDStr) -> usize {
str.bytes.byte_count()
}
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_core_str_get(str: &NSTDStr, range: &NSTDURange) -> NSTDStr {
let len = range.end - range.start;
let start = str.bytes.ptr.raw.add(range.start);
let slice = crate::slice::nstd_core_slice_new(len, str.bytes.ptr.size, start);
nstd_core_str_from_bytes(&slice)
}
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_core_str_is_ascii(str: &NSTDStr) -> NSTDBool {
match core::str::from_utf8(str.bytes.as_byte_slice()) {
Ok(str) => NSTDBool::from(str.is_ascii()),
_ => NSTDBool::NSTD_BOOL_FALSE,
}
}
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_core_str_compare(str1: &NSTDStr, str2: &NSTDStr) -> NSTDBool {
NSTDBool::from(str1.bytes.as_byte_slice() == str2.bytes.as_byte_slice())
}
macro_rules! nstd_str_pat_check {
($fn_name: ident, $method: ident) => {
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn $fn_name(str: &NSTDStr, pattern: &NSTDStr) -> NSTDBool {
let str = str.bytes.as_byte_slice();
let pattern = pattern.bytes.as_byte_slice();
match (core::str::from_utf8(str), core::str::from_utf8(pattern)) {
(Ok(str), Ok(pattern)) => NSTDBool::from(str.$method(pattern)),
_ => NSTDBool::NSTD_BOOL_FALSE,
}
}
};
}
nstd_str_pat_check!(nstd_core_str_contains, contains);
nstd_str_pat_check!(nstd_core_str_starts_with, starts_with);
nstd_str_pat_check!(nstd_core_str_ends_with, ends_with);
macro_rules! nstd_str_find {
($fn_name: ident, $method: ident) => {
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn $fn_name(str: &NSTDStr, pattern: &NSTDStr) -> usize {
let str = str.bytes.as_byte_slice();
let pattern = pattern.bytes.as_byte_slice();
match (core::str::from_utf8(str), core::str::from_utf8(pattern)) {
(Ok(str), Ok(pattern)) => str.$method(pattern).unwrap_or(usize::MAX),
_ => usize::MAX,
}
}
};
}
nstd_str_find!(nstd_core_str_find, find);
nstd_str_find!(nstd_core_str_find_last, rfind);
macro_rules! nstd_core_str_to_case {
($name: ident, $method: ident) => {
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn $name(str: &mut NSTDStr) -> NSTDBool {
match core::str::from_utf8_mut(str.bytes.as_byte_slice_mut()) {
Ok(str) => {
str.$method();
NSTDBool::NSTD_BOOL_FALSE
}
_ => NSTDBool::NSTD_BOOL_TRUE,
}
}
};
}
nstd_core_str_to_case!(nstd_core_str_to_uppercase, make_ascii_uppercase);
nstd_core_str_to_case!(nstd_core_str_to_lowercase, make_ascii_lowercase);
macro_rules! nstd_str_to_num {
($name: ident, $type: ty) => {
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn $name(str: &NSTDStr, is_err: &mut NSTDBool) -> $type {
if let Ok(str) = core::str::from_utf8(str.bytes.as_byte_slice()) {
if let Ok(v) = str.parse::<$type>() {
*is_err = NSTDBool::NSTD_BOOL_FALSE;
return v;
}
}
*is_err = NSTDBool::NSTD_BOOL_TRUE;
<$type>::default()
}
};
}
nstd_str_to_num!(nstd_core_str_to_f32, f32);
nstd_str_to_num!(nstd_core_str_to_f64, f64);
nstd_str_to_num!(nstd_core_str_to_i8, i8);
nstd_str_to_num!(nstd_core_str_to_u8, u8);
nstd_str_to_num!(nstd_core_str_to_i16, i16);
nstd_str_to_num!(nstd_core_str_to_u16, u16);
nstd_str_to_num!(nstd_core_str_to_i32, i32);
nstd_str_to_num!(nstd_core_str_to_u32, u32);
nstd_str_to_num!(nstd_core_str_to_i64, i64);
nstd_str_to_num!(nstd_core_str_to_u64, u64);
nstd_str_to_num!(nstd_core_str_to_isize, isize);
nstd_str_to_num!(nstd_core_str_to_usize, usize);