stringleton_registry/
static_symbol.rs

1use crate::{Site, Symbol};
2
3/// Const-compatible static symbol.
4///
5/// This type is created by the
6/// [`static_sym!(...)`](../stringleton/macro.static_sym.html) macro, and can be
7/// used in const contexts. See the macro documentation for more details.
8///
9/// **CAUTION:** Declarations with `StaticSymbol` must _not_ be used before
10/// static initializers have run, i.e. before `main()`.
11#[derive(Copy, Clone)]
12pub struct StaticSymbol(
13    // Note: Unfortunately, we can't use a `&'static Site` reference directly,
14    // because it messes with a (possibly overzealous?) UB check in the
15    // compiler, probably because `Site` contains an `UnsafeCell`? Going through
16    // a function pointer sidesteps this issue, at very slightly higher cost,
17    // due to the extra indirection.
18    //
19    // This function pointer is always a simple trampoline that simply returns a
20    // static reference into the `.bss` segment.
21    fn() -> &'static Site,
22);
23
24impl StaticSymbol {
25    /// # Safety
26    ///
27    /// Must only be called when the site returned by `f` participates in the
28    /// static table of symbols that will be initialized by a static initializer
29    /// function. This invariant is ensured by the `static_sym!(...)` macro.
30    #[must_use]
31    #[doc(hidden)]
32    pub const unsafe fn new_unchecked(f: fn() -> &'static Site) -> Self {
33        Self(f)
34    }
35}
36
37impl core::ops::Deref for StaticSymbol {
38    type Target = Symbol;
39
40    #[inline(always)]
41    fn deref(&self) -> &Self::Target {
42        unsafe {
43            // SAFETY: Precondition for `StaticSymbol` is that it must only be
44            // used after static initializers have run.
45            self.0().get_ref_after_ctor()
46        }
47    }
48}
49
50impl core::borrow::Borrow<Symbol> for StaticSymbol {
51    #[inline]
52    fn borrow(&self) -> &Symbol {
53        self
54    }
55}
56
57impl AsRef<Symbol> for StaticSymbol {
58    #[inline]
59    fn as_ref(&self) -> &Symbol {
60        self
61    }
62}
63
64impl From<&StaticSymbol> for Symbol {
65    #[inline]
66    fn from(value: &StaticSymbol) -> Self {
67        **value
68    }
69}
70
71impl From<StaticSymbol> for Symbol {
72    #[inline]
73    fn from(value: StaticSymbol) -> Self {
74        *value
75    }
76}
77
78impl PartialEq<Symbol> for StaticSymbol {
79    #[inline]
80    fn eq(&self, other: &Symbol) -> bool {
81        **self == *other
82    }
83}
84
85impl PartialEq<StaticSymbol> for Symbol {
86    #[inline]
87    fn eq(&self, other: &StaticSymbol) -> bool {
88        *self == **other
89    }
90}
91
92impl PartialEq for StaticSymbol {
93    #[inline]
94    fn eq(&self, other: &Self) -> bool {
95        **self == **other
96    }
97}
98
99impl core::fmt::Debug for StaticSymbol {
100    #[inline]
101    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
102        core::fmt::Debug::fmt(&**self, f)
103    }
104}
105
106impl core::fmt::Display for StaticSymbol {
107    #[inline]
108    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
109        core::fmt::Display::fmt(&**self, f)
110    }
111}