kstring/
interned_category.rs1use crate::interned_string::InternedString;
6use core::sync::atomic::AtomicU32;
7
8#[repr(C)]
15pub struct InternedCategory {
16 label: &'static InternedString,
17 index: AtomicU32,
18}
19
20unsafe impl Sync for InternedCategory {}
23unsafe impl Send for InternedCategory {}
24
25impl InternedCategory {
26 pub const INVALID_INDEX: u32 = u32::MAX;
28
29 #[inline]
31 pub const fn new(label: &'static InternedString) -> Self {
32 Self { label, index: AtomicU32::new(Self::INVALID_INDEX) }
33 }
34
35 #[inline]
37 pub fn label(&self) -> &'static InternedString {
38 self.label
39 }
40
41 #[inline]
43 pub fn string(&self) -> &'static core::ffi::CStr {
44 self.label().as_c_str()
45 }
46
47 #[inline]
49 pub fn index(&self) -> u32 {
50 self.index.load(core::sync::atomic::Ordering::Acquire)
51 }
52
53 #[inline]
59 pub fn set_index(&self, index: u32, expected: u32) {
60 let _ = self.index.compare_exchange(
61 expected,
62 index,
63 core::sync::atomic::Ordering::AcqRel,
64 core::sync::atomic::Ordering::Acquire,
65 );
66 }
67}
68
69#[macro_export]
90macro_rules! declare_interned_category {
91 ($var_name:ident, $str_lit:literal) => {
92 #[allow(non_snake_case)]
93 mod $var_name {
94 $crate::declare_interned_string!(STRING, $str_lit);
95
96 #[$crate::interned_category_export_name($str_lit)]
97 #[unsafe(link_section = "__fxt_interned_category_table")]
98 #[used]
99 pub static CATEGORY: $crate::interned_category::InternedCategory =
100 $crate::interned_category::InternedCategory::new(&STRING);
101 }
102
103 pub static $var_name: &$crate::interned_category::InternedCategory = &$var_name::CATEGORY;
104 };
105
106 ($var_name:ident, $str_lit:literal, extern) => {
107 #[allow(non_snake_case)]
108 mod $var_name {
109 $crate::import_category!(CATEGORY, $str_lit);
110 }
111
112 pub static $var_name: &$crate::interned_category::InternedCategory =
113 unsafe { &$var_name::CATEGORY };
114 };
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 declare_interned_category!(TEST_CAT_1, "foo");
122 declare_interned_category!(TEST_CAT_2, "bar");
123
124 #[test]
125 fn test_label_and_string() {
126 assert_eq!(TEST_CAT_1.string(), c"foo");
127 assert_eq!(TEST_CAT_2.string(), c"bar");
128 assert_eq!(TEST_CAT_1.label().as_c_str(), c"foo");
129 }
130
131 #[test]
132 fn test_index_management() {
133 assert_eq!(TEST_CAT_1.index(), InternedCategory::INVALID_INDEX);
134
135 TEST_CAT_1.set_index(42, InternedCategory::INVALID_INDEX);
137 assert_eq!(TEST_CAT_1.index(), 42);
138
139 TEST_CAT_1.set_index(100, 0);
141 assert_eq!(TEST_CAT_1.index(), 42);
142 }
143
144 #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
147 #[test]
148 fn test_linker_section_allocation() {
149 unsafe extern "C" {
150 #[link_name = "__start___fxt_interned_category_table"]
151 static START: InternedCategory;
152 #[link_name = "__stop___fxt_interned_category_table"]
153 static STOP: InternedCategory;
154 }
155
156 let start_ptr = unsafe { &START as *const InternedCategory };
157 let stop_ptr = unsafe { &STOP as *const InternedCategory };
158
159 assert!(start_ptr <= stop_ptr);
161 let diff =
162 (stop_ptr as usize - start_ptr as usize) / core::mem::size_of::<InternedCategory>();
163 assert!(diff >= 2, "Expected at least 2 entries in the table, found {diff}");
164
165 let p1 = TEST_CAT_1 as *const InternedCategory;
167 let p2 = TEST_CAT_2 as *const InternedCategory;
168
169 assert!(
170 p1 >= start_ptr && p1 < stop_ptr,
171 "TEST_CAT_1 pointer {p1:p} is outside bounds [{start_ptr:p}, {stop_ptr:p})"
172 );
173 assert!(
174 p2 >= start_ptr && p2 < stop_ptr,
175 "TEST_CAT_2 pointer {p2:p} is outside bounds [{start_ptr:p}, {stop_ptr:p})"
176 );
177 }
178
179 #[test]
180 fn test_symbol_name_matching() {
181 unsafe extern "C" {
184 #[link_name = "_ZN3fxt8internal23InternedCategoryStorageIJLc102ELc111ELc111EEE17interned_categoryE"]
185 static EXPECTED_SYMBOL: InternedCategory;
186 }
187
188 let p_expected = unsafe { &EXPECTED_SYMBOL as *const InternedCategory };
189 let p_actual = TEST_CAT_1 as *const InternedCategory;
190 assert_eq!(p_actual, p_expected);
191 }
192}