use {
crate::ffi::system as ffi,
core::fmt,
std::error::Error,
widestring::{U32CStr, U32CString, error::Utf32Error},
};
#[derive(Debug)]
#[repr(transparent)]
pub struct SfStr(U32CStr);
impl SfStr {
pub(crate) unsafe fn from_ptr_str<'a>(p: *const u32) -> &'a Self {
unsafe {
let ptr: *const U32CStr = U32CStr::from_ptr_str(p);
&*(ptr as *const Self)
}
}
#[must_use]
#[expect(clippy::unwrap_used)]
pub fn to_rust_string(&self) -> String {
self.0.to_string().unwrap()
}
pub fn try_to_rust_string(&self) -> Result<String, SfStrConvError> {
match self.0.to_string() {
Ok(string) => Ok(string),
Err(utf32error) => Err(SfStrConvError::from_utf32error(utf32error)),
}
}
pub(crate) fn as_ptr(&self) -> *const u32 {
self.0.as_ptr()
}
}
pub trait SfStrConv {
#[doc(hidden)]
fn with_as_sfstr<F, R>(self, fun: F) -> R
where
F: FnOnce(&SfStr) -> R;
}
impl SfStrConv for &SfStr {
fn with_as_sfstr<F, R>(self, fun: F) -> R
where
F: FnOnce(&SfStr) -> R,
{
fun(self)
}
}
impl SfStrConv for &str {
fn with_as_sfstr<F, R>(self, fun: F) -> R
where
F: FnOnce(&SfStr) -> R,
{
#[expect(clippy::unwrap_used)]
let uc_string = U32CString::from_str(self).unwrap();
let uc_str_ptr: *const U32CStr = uc_string.as_ucstr();
let sf_str: &SfStr = unsafe { &*(uc_str_ptr as *const SfStr) };
fun(sf_str)
}
}
impl SfStrConv for &String {
fn with_as_sfstr<F, R>(self, fun: F) -> R
where
F: FnOnce(&SfStr) -> R,
{
let str: &str = self;
str.with_as_sfstr(fun)
}
}
#[derive(Debug)]
pub struct SfStrConvError(Utf32Error);
impl SfStrConvError {
fn from_utf32error(value: Utf32Error) -> Self {
Self(value)
}
pub fn index(&self) -> usize {
self.0.index()
}
#[must_use]
pub fn into_vec(self) -> Option<Vec<u32>> {
self.0.into_vec()
}
}
impl Error for SfStrConvError {}
impl fmt::Display for SfStrConvError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}
decl_opaque! {
pub SfString;
}
impl SfString {
fn data(&self) -> &[u32] {
unsafe {
let len = ffi::sfString_getLength(self);
let data = ffi::sfString_getData(self);
std::slice::from_raw_parts(data, len)
}
}
}
impl fmt::Display for SfString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let data = self.data();
let ustr = widestring::U32Str::from_slice(data);
write!(f, "{}", ustr.to_string_lossy())
}
}