Skip to main content

uika_runtime/
fname.rs

1// FName: ergonomic wrapper around FNameHandle.
2// Provides construction from &str and Display for string conversion.
3
4use std::fmt;
5
6use uika_ffi::FNameHandle;
7
8use crate::api::api;
9use crate::error::check_ffi;
10
11/// A UE FName value. Copy-able, hashable, and comparable.
12///
13/// FName is UE's interned string type — cheap to copy and compare,
14/// but creation and string conversion require FFI calls.
15#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
16pub struct FName(pub FNameHandle);
17
18impl FName {
19    /// The "None" name (index 0).
20    pub const NONE: FName = FName(FNameHandle(0));
21
22    /// Create an FName from a string.
23    pub fn new(name: &str) -> Self {
24        let handle = unsafe {
25            ((*api().core).make_fname)(name.as_ptr(), name.len() as u32)
26        };
27        FName(handle)
28    }
29
30    /// Get the underlying FFI handle.
31    #[inline]
32    pub fn handle(&self) -> FNameHandle {
33        self.0
34    }
35
36    /// Check if this is the "None" name.
37    #[inline]
38    pub fn is_none(&self) -> bool {
39        self.0 .0 == 0
40    }
41
42    /// Convert to a String. Returns an error only if the FFI call fails.
43    pub fn to_string_lossy(&self) -> String {
44        // Stack buffer — 256 bytes is enough for virtually all FNames.
45        let mut buf = [0u8; 256];
46        let mut out_len: u32 = 0;
47        let code = unsafe {
48            ((*api().core).fname_to_string)(
49                self.0,
50                buf.as_mut_ptr(),
51                buf.len() as u32,
52                &mut out_len,
53            )
54        };
55        if check_ffi(code).is_err() {
56            return String::from("<invalid FName>");
57        }
58        std::str::from_utf8(&buf[..out_len as usize])
59            .map(|s| s.to_owned())
60            .unwrap_or_else(|_| String::from("<invalid UTF-8>"))
61    }
62}
63
64impl Default for FName {
65    fn default() -> Self {
66        FName::NONE
67    }
68}
69
70impl fmt::Display for FName {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        write!(f, "{}", self.to_string_lossy())
73    }
74}
75
76impl PartialEq<&str> for FName {
77    fn eq(&self, other: &&str) -> bool {
78        self.to_string_lossy() == *other
79    }
80}
81
82impl From<&str> for FName {
83    fn from(s: &str) -> Self {
84        FName::new(s)
85    }
86}
87
88impl From<FName> for FNameHandle {
89    fn from(name: FName) -> FNameHandle {
90        name.0
91    }
92}
93
94impl From<FNameHandle> for FName {
95    fn from(handle: FNameHandle) -> FName {
96        FName(handle)
97    }
98}