use core_extensions::type_level_bool::{Boolean, False, True};
use std::{
fmt,
marker::PhantomData,
num,
pin::Pin,
ptr::NonNull,
sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize},
};
use crate::std_types::{RNone, RSome, StaticSlice, StaticStr};
use super::{LifetimeIndex, RustPrimitive, TLData, TLField, TypeLayout, TypeLayoutParams};
pub unsafe trait StableAbi {
type IsNonZeroType: Boolean;
const LAYOUT: &'static TypeLayout;
const ABI_INFO: &'static AbiInfoWrapper = {
let info = AbiInfo {
prefix_kind: false,
is_nonzero: <Self::IsNonZeroType as Boolean>::VALUE,
layout: Self::LAYOUT,
};
&AbiInfoWrapper::new(info)
};
}
#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(C)]
#[derive(StableAbi)]
#[sabi(inside_abi_stable_crate)]
pub struct AbiInfoWrapper {
inner: AbiInfo,
_priv: (),
}
impl AbiInfoWrapper {
const fn new(inner: AbiInfo) -> Self {
Self { inner, _priv: () }
}
pub const unsafe fn new_unchecked(inner: AbiInfo) -> Self {
Self::new(inner)
}
pub const fn get(&self) -> &AbiInfo {
&self.inner
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(C)]
#[derive(StableAbi)]
#[sabi(inside_abi_stable_crate)]
pub struct AbiInfo {
pub prefix_kind: bool,
pub is_nonzero: bool,
pub layout: &'static TypeLayout,
}
#[derive(Copy, Clone)]
#[repr(transparent)]
#[derive(StableAbi)]
#[sabi(inside_abi_stable_crate)]
pub struct GetAbiInfo {
abi_info: extern "C" fn() -> &'static AbiInfo,
}
impl fmt::Debug for GetAbiInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.get(), f)
}
}
impl GetAbiInfo {
pub fn get(self) -> &'static AbiInfo {
(self.abi_info)()
}
}
pub unsafe trait MakeGetAbiInfo<B> {
const CONST: GetAbiInfo;
}
unsafe impl<T> MakeGetAbiInfo<StableAbi_Bound> for T
where
T: StableAbi,
{
const CONST: GetAbiInfo = GetAbiInfo {
abi_info: get_abi_info::<T>,
};
}
unsafe impl<T> MakeGetAbiInfo<UnsafeOpaqueField_Bound> for T {
const CONST: GetAbiInfo = GetAbiInfo {
abi_info: get_abi_info::<UnsafeOpaqueField<T>>,
};
}
#[allow(non_camel_case_types)]
pub struct StableAbi_Bound;
#[allow(non_camel_case_types)]
pub struct UnsafeOpaqueField_Bound;
pub extern "C" fn get_abi_info<T>() -> &'static AbiInfo
where
T: StableAbi,
{
T::ABI_INFO.get()
}
unsafe impl<T> StableAbi for PhantomData<T> {
type IsNonZeroType = False;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_std_lib_phantom::<Self>(
"PhantomData",
RNone,
TLData::Primitive,
tl_genparams!(;;),
&[],
);
}
unsafe impl StableAbi for () {
type IsNonZeroType = False;
const LAYOUT: &'static TypeLayout =
&TypeLayout::from_std_lib::<Self>("()", TLData::Primitive, tl_genparams!(;;));
}
unsafe impl<'a, T> StableAbi for &'a T
where
T: 'a + StableAbi,
{
type IsNonZeroType = True;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_std_lib_phantom::<Self>(
"&",
RSome(RustPrimitive::Reference),
TLData::Primitive,
tl_genparams!('a;T;),
&[TLField::new(
"0",
&[LifetimeIndex::Param(0)],
<T as MakeGetAbiInfo<StableAbi_Bound>>::CONST,
)],
);
}
unsafe impl<'a, T> StableAbi for &'a mut T
where
T: 'a + StableAbi,
{
type IsNonZeroType = True;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_std_lib_phantom::<Self>(
"&mut",
RSome(RustPrimitive::MutReference),
TLData::Primitive,
tl_genparams!('a;T;),
&[TLField::new(
"0",
&[LifetimeIndex::Param(0)],
<T as MakeGetAbiInfo<StableAbi_Bound>>::CONST,
)],
);
}
unsafe impl<T> StableAbi for NonNull<T>
where
T: StableAbi,
{
type IsNonZeroType = True;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_std_lib_phantom::<Self>(
"NonNull",
RNone,
TLData::Primitive,
tl_genparams!(;T;),
&[TLField::new(
"0",
&[],
<T as MakeGetAbiInfo<StableAbi_Bound>>::CONST,
)],
);
}
unsafe impl<T> StableAbi for AtomicPtr<T>
where
T: StableAbi,
{
type IsNonZeroType = False;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_std_lib_phantom::<Self>(
"AtomicPtr",
RNone,
TLData::Primitive,
tl_genparams!(;T;),
&[TLField::new(
"0",
&[],
<T as MakeGetAbiInfo<StableAbi_Bound>>::CONST,
)],
);
}
unsafe impl<T> StableAbi for *const T
where
T: StableAbi,
{
type IsNonZeroType = False;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_std_lib_phantom::<Self>(
"*const",
RSome(RustPrimitive::ConstPtr),
TLData::Primitive,
tl_genparams!(;T;),
&[TLField::new(
"0",
&[],
<T as MakeGetAbiInfo<StableAbi_Bound>>::CONST,
)],
);
}
unsafe impl<T> StableAbi for *mut T
where
T: StableAbi,
{
type IsNonZeroType = False;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_std_lib_phantom::<Self>(
"*mut",
RSome(RustPrimitive::MutPtr),
TLData::Primitive,
tl_genparams!(;T;),
&[TLField::new(
"0",
&[],
<T as MakeGetAbiInfo<StableAbi_Bound>>::CONST,
)],
);
}
macro_rules! impl_stable_abi_array {
($($size:expr),*)=>{
$(
unsafe impl<T> StableAbi for [T;$size]
where T:StableAbi
{
type IsNonZeroType=False;
const LAYOUT:&'static TypeLayout=&TypeLayout::from_std_lib_phantom::<Self>(
stringify!(concat!("[_;",stringify!($size),"]")),
RSome(RustPrimitive::Array),
TLData::Primitive,
tl_genparams!(;T;$size),
&[TLField::new("0", &[], <T as MakeGetAbiInfo<StableAbi_Bound>>::CONST)],
);
}
)*
}
}
impl_stable_abi_array! {
00,01,02,03,04,05,06,07,08,09,
10,11,12,13,14,15,16,17,18,19,
20,21,22,23,24,25,26,27,28,29,
30,31,32
}
unsafe impl<T> StableAbi for Option<T>
where
T: StableAbi<IsNonZeroType = True>,
{
type IsNonZeroType = False;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_std_lib_phantom::<Self>(
"Option",
RNone,
TLData::Primitive,
tl_genparams!(;T;),
&[TLField::new(
"0",
&[],
<T as MakeGetAbiInfo<StableAbi_Bound>>::CONST,
)],
);
}
macro_rules! impl_for_concrete {
(
zeroable=[$( $zeroable:ty ,)*]
nonzero=[ $( $nonzero:ty ,)* ]
) => (
$(
unsafe impl StableAbi for $zeroable {
type IsNonZeroType=False;
const LAYOUT:&'static TypeLayout=&TypeLayout::from_std_lib::<Self>(
stringify!($zeroable),
TLData::Primitive,
tl_genparams!(;;),
);
}
)*
$(
unsafe impl StableAbi for $nonzero {
type IsNonZeroType=True;
const LAYOUT:&'static TypeLayout=&TypeLayout::from_std_lib::<Self>(
stringify!($nonzero),
TLData::Primitive,
tl_genparams!(;;),
);
}
)*
)
}
impl_for_concrete! {
zeroable=[
u8,i8,
u16,i16,
u32,i32,
u64,i64,
usize,isize,
bool,
AtomicBool,
AtomicIsize,
AtomicUsize,
]
nonzero=[
num::NonZeroU8,
num::NonZeroU16,
num::NonZeroU32,
num::NonZeroU64,
num::NonZeroUsize,
]
}
#[cfg(any(rust_1_34,feature="rust_1_34"))]
mod rust_1_34_impls{
use super::*;
use std::sync::atomic;
use core::num as core_num;
impl_for_concrete! {
zeroable=[
atomic::AtomicI16,
atomic::AtomicI32,
atomic::AtomicI64,
atomic::AtomicI8,
atomic::AtomicU16,
atomic::AtomicU32,
atomic::AtomicU64,
atomic::AtomicU8,
]
nonzero=[
core_num::NonZeroI8,
core_num::NonZeroI16,
core_num::NonZeroI32,
core_num::NonZeroI64,
core_num::NonZeroIsize,
]
}
}
unsafe impl<N> StableAbi for num::Wrapping<N>
where
N: StableAbi,
{
type IsNonZeroType = N::IsNonZeroType;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_std_lib::<Self>(
"num::Wrapping",
TLData::ReprTransparent(N::ABI_INFO.get()),
tl_genparams!(;N;),
);
}
unsafe impl<P> StableAbi for Pin<P>
where
P: StableAbi,
{
type IsNonZeroType = P::IsNonZeroType;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_std_lib::<Self>(
"Pin",
TLData::ReprTransparent(P::ABI_INFO.get()),
tl_genparams!(;P;),
);
}
unsafe impl StableAbi for extern "C" fn() {
type IsNonZeroType = True;
const LAYOUT: &'static TypeLayout = EMPTY_EXTERN_FN_LAYOUT;
}
unsafe impl StableAbi for unsafe extern "C" fn() {
type IsNonZeroType = True;
const LAYOUT: &'static TypeLayout = EMPTY_EXTERN_FN_LAYOUT;
}
const EMPTY_EXTERN_FN_LAYOUT: &'static TypeLayout =
&TypeLayout::from_params::<extern "C" fn()>(TypeLayoutParams {
name: "AFunctionPointer",
package: env!("CARGO_PKG_NAME"),
package_version: crate::version::VersionStrings {
major: StaticStr::new(env!("CARGO_PKG_VERSION_MAJOR")),
minor: StaticStr::new(env!("CARGO_PKG_VERSION_MINOR")),
patch: StaticStr::new(env!("CARGO_PKG_VERSION_PATCH")),
},
file:"<unavailable>",
line:0,
data: TLData::Struct {
fields: StaticSlice::new(&[]),
},
generics: tl_genparams!(;;),
phantom_fields: &[],
});
#[repr(transparent)]
pub struct UnsafeOpaqueField<T>(T);
unsafe impl<T> StableAbi for UnsafeOpaqueField<T> {
type IsNonZeroType = False;
const LAYOUT: &'static TypeLayout = &TypeLayout::from_params::<Self>(TypeLayoutParams {
name: "OpaqueField",
package: env!("CARGO_PKG_NAME"),
package_version: crate::version::VersionStrings {
major: StaticStr::new(env!("CARGO_PKG_VERSION_MAJOR")),
minor: StaticStr::new(env!("CARGO_PKG_VERSION_MINOR")),
patch: StaticStr::new(env!("CARGO_PKG_VERSION_PATCH")),
},
file:"<unavailable>",
line:0,
data: TLData::Primitive,
generics: tl_genparams!(;;),
phantom_fields: &[],
});
}