godot_ffi/
string_cache.rs1use std::collections::HashMap;
9use std::mem::MaybeUninit;
10use std::ptr;
11
12use crate as sys;
13
14pub struct StringCache<'a> {
16 instances_by_str: HashMap<&'static str, Box<sys::types::OpaqueStringName>>,
18 interface: &'a sys::GDExtensionInterface,
19 builtin_lifecycle: &'a sys::BuiltinLifecycleTable,
20}
21
22impl<'a> StringCache<'a> {
23 pub fn new(
24 interface: &'a sys::GDExtensionInterface,
25 builtin_lifecycle: &'a sys::BuiltinLifecycleTable,
26 ) -> Self {
27 Self {
28 instances_by_str: HashMap::new(),
29 interface,
30 builtin_lifecycle,
31 }
32 }
33
34 pub fn fetch(&mut self, key: &'static str) -> sys::GDExtensionStringNamePtr {
36 assert!(key.is_ascii(), "string is not ASCII: {key}");
37
38 if let Some(opaque_box) = self.instances_by_str.get_mut(key) {
40 return box_to_sname_ptr(opaque_box);
41 }
42
43 let mut sname = MaybeUninit::<sys::types::OpaqueStringName>::uninit();
44 let sname_ptr = sname.as_mut_ptr();
45
46 unsafe {
48 let string_name_new_with_utf8_chars_and_len = self
49 .interface
50 .string_name_new_with_utf8_chars_and_len
51 .unwrap_unchecked();
52
53 string_name_new_with_utf8_chars_and_len(
56 sname_uninit_ptr(sname_ptr),
57 key.as_ptr() as *const std::os::raw::c_char,
58 key.len() as sys::GDExtensionInt,
59 );
60 }
61
62 let opaque = unsafe { sname.assume_init() };
64
65 let mut opaque_box = Box::new(opaque);
66 let sname_ptr = box_to_sname_ptr(&mut opaque_box);
67
68 self.instances_by_str.insert(key, opaque_box);
69 sname_ptr
70 }
71}
72
73impl Drop for StringCache<'_> {
75 fn drop(&mut self) {
76 let string_name_destroy = self.builtin_lifecycle.string_name_destroy;
77
78 unsafe {
79 for (_, mut opaque_box) in self.instances_by_str.drain() {
80 let opaque_ptr = ptr::addr_of_mut!(*opaque_box);
81 string_name_destroy(sname_type_ptr(opaque_ptr));
82 }
83 }
84 }
85}
86
87fn box_to_sname_ptr(
93 boxed: &mut Box<sys::types::OpaqueStringName>,
94) -> sys::GDExtensionStringNamePtr {
95 let opaque_ptr = ptr::addr_of_mut!(**boxed);
96 opaque_ptr as sys::GDExtensionStringNamePtr
97}
98
99unsafe fn sname_uninit_ptr(
100 opaque_ptr: *mut sys::types::OpaqueStringName,
101) -> sys::GDExtensionUninitializedStringNamePtr {
102 opaque_ptr as sys::GDExtensionUninitializedStringNamePtr
103}
104
105unsafe fn sname_type_ptr(opaque_ptr: *mut sys::types::OpaqueStringName) -> sys::GDExtensionTypePtr {
106 opaque_ptr as sys::GDExtensionTypePtr
107}