macro_rules! sym {
($sym:ident) => { ... };
($sym:literal) => { ... };
(@impl $sym:expr) => { ... };
}
Expand description
Create a literal symbol from a literal identifier or string
Symbols created with the sym!(...)
macro are statically
allocated and deduplicated on program startup. This means that there is no
discernible overhead at the point of use, making them suitable even in long
chains of if
statements and inner loops.
IMPORTANT: For this macro to work in a particular crate, the
enable!()
macro must appear exactly once in the crate’s
root. This creates the global registration table at link-time.
§Safety
This macro is safe (and performant) to use everywhere, with important caveats:
-
If you are using “static initializers” (code that runs before
main()
, like through thector
crate), this macro must NOT be called in such a static initializer function. See https://github.com/mmastrac/rust-ctor/issues/159. UsingSymbol::new()
in such a function is fine. -
If you are using C-style dynamic libraries (
cdylib
crate type), those libraries must use thestringleton-dylib
crate instead ofstringleton
. -
If you are loading dynamic libraries at runtime (i.e., outside of Cargo’s dependency graph), the host crate must also use the
stringleton-dylib
crate instead ofstringleton
.
§Low-level details
This macro creates an entry in a per-crate linkme
“distributed slice”, as
well as a static initializer called by the OS when the current crate is
loaded at runtime (before main()
), either as part of an executable or as
part of a dynamic library.
On x86-64 and ARM64, this macro is guaranteed to compile into a single
relaxed atomic memory load instruction from an offset in the .bss
segment.
On x86, relaxed atomic load instructions have no additional overhead
compared to non-atomic loads.
Internally, this uses the linkme
and ctor
crates to register this
callsite in static binary memory and initialize it on startup. However, when
running under Miri (or other platforms not supported by linkme
), the
implementation falls back on a slower implementation that effectively calls
Symbol::new()
every time, which takes a global read-lock.
When the debug-assertions
feature is enabled, there is an additional check
that panics if the call site has not been populated by a static ctor. This
assertion will only be triggered if the current platform does not support
static initializers.