use std::fmt::{Display, Formatter}; use std::sync::OnceLock; use widestring::{WideCStr, WideCString}; use crate::{Add, Container}; use crate::t_array::TArray; type FStringPrintf = fn(handle: usize, fmt: *const u16); static FSTRING_PRINTF: OnceLock<usize> = OnceLock::new(); pub trait Printf<T: ?Sized> { /// Since rust does not support varargs in functions, it is recommended to call format! fn printf<A: AsRef<T>>(handle: usize, fmt: A); } pub struct FString(pub(crate) TArray); impl FString { pub fn set_f_string_printf_ptr(f_string_printf: usize) { FSTRING_PRINTF.set(f_string_printf).unwrap(); } } impl Printf<str> for FString { #[inline(always)] fn printf<A: AsRef<str>>(handle: usize, fmt: A) { let tmp = WideCString::from_str(fmt).unwrap(); unsafe { std::mem::transmute::<usize, FStringPrintf>(*fstring_printf())( handle, tmp.as_ucstr().as_ptr(), ); } } } impl<'a> Container<&'a WideCStr> for FString { #[inline(always)] fn read_container(&self) -> &'a WideCStr { unsafe { WideCStr::from_ptr(self.0.data_ptr as *const u16, self.0.len as usize - 1) }.unwrap() } } impl Add for FString { fn add(&mut self, other: &mut Self) -> &mut Self { let old_len = self.0.resize_grow(Some(other.0.len)); let src = unsafe { std::slice::from_raw_parts_mut(other.0.data_ptr as *mut u16, other.0.len as usize) }; let dst = unsafe { std::slice::from_raw_parts_mut(self.0.data_ptr as *mut u16, self.0.len as usize) }; dst[old_len as usize..other.0.len as usize].copy_from_slice(src); // Clear the header of the original container other.0.release_header_stack(); self } } impl Display for FString { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.read_container().to_string_lossy()) } } #[inline(always)] fn fstring_printf() -> &'static usize { FSTRING_PRINTF.get().unwrap() }