unreal-niggery-rs/src/f_string.rs
2024-12-30 19:29:48 +01:00

72 lines
2 KiB
Rust

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()
}