use std::{
ffi::{c_char, c_void},
fmt::Debug,
hash::{Hash, Hasher},
marker::PhantomData,
ptr::NonNull,
};
use jl_sys::jl_symbol_n;
use crate::{
data::{
managed::{private::ManagedPriv, symbol::Symbol},
types::construct_type::{ConstructType, TypeVarName},
},
memory::target::{Target, unrooted::Unrooted},
prelude::Managed,
private::Private,
};
#[macro_export]
macro_rules! define_static_symbol {
(for $name:ident, $sym:literal) => {
unsafe impl $crate::data::managed::symbol::static_symbol::StaticSymbol for $name {
#[inline]
fn get_symbol<'target, Tgt: $crate::memory::target::Target<'target>>(_: &Tgt) -> $crate::data::managed::symbol::Symbol<'target> {
static PTR: ::std::sync::atomic::AtomicPtr<::std::ffi::c_void> = ::std::sync::atomic::AtomicPtr::new(::std::ptr::null_mut());
#[cold]
#[inline(never)]
unsafe fn init() -> $crate::data::managed::symbol::Symbol<'static> { unsafe {
const N: usize = $sym.as_bytes().len();
const INNER_PTR: *mut ::std::ffi::c_char = $sym.as_ptr() as *const ::std::ffi::c_char as *mut ::std::ffi::c_char;
let ptr = $crate::data::managed::symbol::static_symbol::new_symbol(INNER_PTR, N);
PTR.store(ptr, ::std::sync::atomic::Ordering::Relaxed);
$crate::data::managed::symbol::static_symbol::convert_void_ptr(ptr)
}}
fn inner() -> $crate::data::managed::symbol::Symbol<'static> {
let ptr = PTR.load(::std::sync::atomic::Ordering::Relaxed);
unsafe {
if ptr.is_null() {
init()
} else {
$crate::data::managed::symbol::static_symbol::convert_void_ptr(ptr)
}
}
}
inner()
}
}
};
($(#[$meta:meta])* $vis:vis $name:ident, $sym:literal) => {
$(#[$meta])*
$vis struct $name;
$crate::define_static_symbol!(for $name, $sym);
};
}
#[macro_export]
macro_rules! define_static_binary_symbol {
(for $name:ident, $sym:literal) => {
unsafe impl $crate::data::managed::symbol::static_symbol::StaticSymbol for $name {
#[inline]
fn get_symbol<'target, Tgt: $crate::memory::target::Target<'target>>(_: &Tgt) -> $crate::data::managed::symbol::Symbol<'target> {
static PTR: ::std::sync::atomic::AtomicPtr<::std::ffi::c_void> = ::std::sync::atomic::AtomicPtr::new(::std::ptr::null_mut());
#[cold]
#[inline(never)]
unsafe fn init() -> $crate::data::managed::symbol::Symbol<'static> {
const N: usize = $sym.len();
const INNER_PTR: *mut ::std::ffi::c_char = $sym.as_ptr() as *const ::std::ffi::c_char as *mut ::std::ffi::c_char;
let ptr = $crate::data::managed::symbol::static_symbol::new_symbol(INNER_PTR, N);
PTR.store(ptr, ::std::sync::atomic::Ordering::Relaxed);
$crate::data::managed::symbol::static_symbol::convert_void_ptr(ptr)
}
fn inner() -> $crate::data::managed::symbol::Symbol<'static> {
let ptr = PTR.load(::std::sync::atomic::Ordering::Relaxed);
unsafe {
if ptr.is_null() {
init()
} else {
$crate::data::managed::symbol::static_symbol::convert_void_ptr(ptr)
}
}
};
inner()
}
}
};
($(#[$meta:meta])* $vis:vis $name:ident, $sym:literal) => {
$(#[$meta])*
$vis struct $name;
$crate::define_static_binary_symbol!(for $name, $sym);
};
}
pub unsafe trait StaticSymbol: 'static {
fn get_symbol<'target, Tgt: Target<'target>>(target: &Tgt) -> Symbol<'target>;
}
#[repr(transparent)]
pub struct Sym<'target, S>(S, PhantomData<&'target ()>);
impl<'target, S: StaticSymbol> Sym<'target, S> {
#[inline]
pub fn new<Tgt>(_: &Tgt, s: S) -> Self
where
Tgt: Target<'target>,
{
Sym(s, PhantomData)
}
#[inline]
pub fn take(self) -> S {
self.0
}
}
#[inline]
pub fn sym<'target, S, Tgt>(_: &Tgt) -> Sym<'target, PhantomData<S>>
where
S: StaticSymbol,
Tgt: Target<'target>,
{
Sym(PhantomData, PhantomData)
}
unsafe impl<S: StaticSymbol> ConstructType for Sym<'_, S> {
type Static = Sym<'static, S>;
const CACHEABLE: bool = false;
#[inline]
fn construct_type_uncached<'target, Tgt>(
target: Tgt,
) -> crate::prelude::ValueData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
{
S::get_symbol(&target).as_value().root(target)
}
#[inline]
fn construct_type_with_env_uncached<'target, Tgt>(
target: Tgt,
_: &crate::data::types::construct_type::TypeVarEnv,
) -> crate::prelude::ValueData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
{
S::get_symbol(&target).as_value().root(target)
}
#[inline]
fn base_type<'target, Tgt>(_: &Tgt) -> Option<crate::prelude::Value<'target, 'static>>
where
Tgt: Target<'target>,
{
None
}
}
unsafe impl<S: StaticSymbol> ConstructType for Sym<'_, PhantomData<S>> {
type Static = Sym<'static, S>;
const CACHEABLE: bool = false;
#[inline]
fn construct_type_uncached<'target, Tgt>(
target: Tgt,
) -> crate::prelude::ValueData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
{
S::get_symbol(&target).as_value().root(target)
}
#[inline]
fn construct_type_with_env_uncached<'target, Tgt>(
target: Tgt,
_: &crate::data::types::construct_type::TypeVarEnv,
) -> crate::prelude::ValueData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
{
S::get_symbol(&target).as_value().root(target)
}
#[inline]
fn base_type<'target, Tgt>(_: &Tgt) -> Option<crate::prelude::Value<'target, 'static>>
where
Tgt: Target<'target>,
{
None
}
}
impl<S: StaticSymbol> TypeVarName for Sym<'static, S> {
#[inline]
fn symbol<'target, Tgt: Target<'target>>(target: &Tgt) -> Symbol<'target> {
S::get_symbol(target)
}
}
impl<S: StaticSymbol> TypeVarName for Sym<'static, PhantomData<S>> {
#[inline]
fn symbol<'target, Tgt: Target<'target>>(target: &Tgt) -> Symbol<'target> {
S::get_symbol(target)
}
}
impl<S: StaticSymbol> Hash for Sym<'_, S> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
unsafe {
let unrooted = Unrooted::new();
let s = S::get_symbol(&unrooted);
<Symbol as Hash>::hash(&s, state)
}
}
}
impl<S: StaticSymbol> Hash for Sym<'_, PhantomData<S>> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
unsafe {
let unrooted = Unrooted::new();
let s = S::get_symbol(&unrooted);
<Symbol as Hash>::hash(&s, state)
}
}
}
impl<S: StaticSymbol> Debug for Sym<'_, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unsafe {
f.debug_tuple("Sym")
.field(&S::get_symbol(&Unrooted::new()))
.finish()
}
}
}
impl<S: StaticSymbol> Debug for Sym<'_, PhantomData<S>> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unsafe {
f.debug_tuple("Sym")
.field(&S::get_symbol(&Unrooted::new()))
.finish()
}
}
}
impl<S: StaticSymbol, T: StaticSymbol> PartialEq<T> for Sym<'_, S> {
fn eq(&self, _: &T) -> bool {
unsafe {
let unrooted = Unrooted::new();
let this = S::get_symbol(&unrooted);
let other = T::get_symbol(&unrooted);
this == other
}
}
}
impl<S: StaticSymbol, T: StaticSymbol> PartialEq<Sym<'_, T>> for Sym<'_, S> {
fn eq(&self, _: &Sym<T>) -> bool {
unsafe {
let unrooted = Unrooted::new();
let this = S::get_symbol(&unrooted);
let other = T::get_symbol(&unrooted);
this == other
}
}
}
impl<S: StaticSymbol, T: StaticSymbol> PartialEq<Sym<'_, PhantomData<T>>> for Sym<'_, S> {
fn eq(&self, _: &Sym<PhantomData<T>>) -> bool {
unsafe {
let unrooted = Unrooted::new();
let this = S::get_symbol(&unrooted);
let other = T::get_symbol(&unrooted);
this == other
}
}
}
impl<S: StaticSymbol, T: StaticSymbol> PartialEq<T> for Sym<'_, PhantomData<S>> {
fn eq(&self, _: &T) -> bool {
unsafe {
let unrooted = Unrooted::new();
let this = S::get_symbol(&unrooted);
let other = T::get_symbol(&unrooted);
this == other
}
}
}
impl<S: StaticSymbol, T: StaticSymbol> PartialEq<Sym<'_, T>> for Sym<'_, PhantomData<S>> {
fn eq(&self, _: &Sym<T>) -> bool {
unsafe {
let unrooted = Unrooted::new();
let this = S::get_symbol(&unrooted);
let other = T::get_symbol(&unrooted);
this == other
}
}
}
impl<S: StaticSymbol, T: StaticSymbol> PartialEq<Sym<'_, PhantomData<T>>>
for Sym<'_, PhantomData<S>>
{
fn eq(&self, _: &Sym<PhantomData<T>>) -> bool {
unsafe {
let unrooted = Unrooted::new();
let this = S::get_symbol(&unrooted);
let other = T::get_symbol(&unrooted);
this == other
}
}
}
impl<S: StaticSymbol> PartialEq<Symbol<'_>> for Sym<'_, S> {
fn eq(&self, other: &Symbol<'_>) -> bool {
unsafe {
let unrooted = Unrooted::new();
let this = S::get_symbol(&unrooted);
this.0 == other.0
}
}
}
impl<S: StaticSymbol> PartialEq<Symbol<'_>> for Sym<'_, PhantomData<S>> {
fn eq(&self, other: &Symbol<'_>) -> bool {
unsafe {
let unrooted = Unrooted::new();
let this = S::get_symbol(&unrooted);
this.0 == other.0
}
}
}
#[doc(hidden)]
#[inline(always)]
pub unsafe fn convert_void_ptr(ptr: *mut c_void) -> Symbol<'static> {
unsafe { Symbol::wrap_non_null(NonNull::new_unchecked(ptr as *mut _), Private) }
}
#[doc(hidden)]
#[inline(always)]
pub unsafe fn new_symbol<'target>(ptr: *mut c_char, len: usize) -> *mut c_void {
unsafe { jl_symbol_n(ptr, len) as *mut _ }
}
define_static_symbol!(pub NSym, "N");
define_static_symbol!(pub TSym, "T");