nsi_ffi_wrap/token.rs
1//! Token type for attribute and type name strings.
2//!
3//! The `Token` type wraps attribute/type name strings with different backing
4//! implementations based on feature flags:
5//!
6//! - Default (`Ustr`): Interned strings with zero-cost C pointer conversion
7//! - `cstring_tokens`: Uses `CString` for non-interned C strings
8//!
9//! Note: Unlike handles which change frequently, tokens (attribute names,
10//! type names) are typically repeated many times, making interning beneficial
11//! by default.
12
13use std::ffi::c_char;
14
15// ─── Ustr backing (interned strings, default) ───────────────────────────────
16
17#[cfg(not(feature = "cstring_tokens"))]
18mod inner {
19 use super::*;
20 use ustr::{Ustr, ustr};
21
22 /// A token string backed by an interned `Ustr`.
23 ///
24 /// This provides O(1) equality checks and zero-cost conversion to C strings.
25 /// This is the default because tokens (attribute names, type names) are
26 /// typically repeated many times in a scene, making interning beneficial.
27 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28 pub struct Token(Ustr);
29
30 impl Token {
31 /// Create a new token from a string slice.
32 #[inline(always)]
33 pub fn new(s: &str) -> Self {
34 Self(ustr(s))
35 }
36
37 /// Get the token as a string slice.
38 #[inline(always)]
39 pub fn as_str(&self) -> &str {
40 self.0.as_str()
41 }
42
43 /// Get the token as a C string pointer.
44 ///
45 /// The returned pointer is valid for the lifetime of the `Ustr` cache
46 /// (effectively 'static for interned strings).
47 #[inline(always)]
48 pub fn as_char_ptr(&self) -> *const c_char {
49 self.0.as_char_ptr()
50 }
51 }
52
53 impl From<&str> for Token {
54 #[inline(always)]
55 fn from(s: &str) -> Self {
56 Self::new(s)
57 }
58 }
59
60 impl PartialEq<Ustr> for Token {
61 fn eq(&self, other: &Ustr) -> bool {
62 self.0 == *other
63 }
64 }
65}
66
67// ─── CString backing (owned C strings) ──────────────────────────────────────
68
69#[cfg(feature = "cstring_tokens")]
70mod inner {
71 use super::*;
72 use std::ffi::CString;
73
74 /// A token string backed by an owned `CString`.
75 ///
76 /// This provides conversion to C strings without interning.
77 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
78 pub struct Token(CString);
79
80 impl Token {
81 /// Create a new token from a string slice.
82 ///
83 /// # Panics
84 /// Panics if the string contains interior NUL bytes.
85 #[inline(always)]
86 pub fn new(s: &str) -> Self {
87 Self(CString::new(s).expect("Token string contains NUL byte"))
88 }
89
90 /// Get the token as a string slice.
91 #[inline(always)]
92 pub fn as_str(&self) -> &str {
93 self.0.to_str().expect("Token contains invalid UTF-8")
94 }
95
96 /// Get the token as a C string pointer.
97 ///
98 /// The returned pointer is valid for the lifetime of this `Token`.
99 #[inline(always)]
100 pub fn as_char_ptr(&self) -> *const c_char {
101 self.0.as_ptr()
102 }
103 }
104
105 impl From<&str> for Token {
106 #[inline(always)]
107 fn from(s: &str) -> Self {
108 Self::new(s)
109 }
110 }
111}
112
113pub use inner::Token;