use core::{cell::UnsafeCell, num::NonZero as StdNonZero, num::NonZeroU8, ops::Add};
use std::ffi::{CStr, c_void};
use rust_spec::{
RustSpec, Stable, Unstable,
drop::{AutoDrop, CustomDrop, NoDrop},
layout::{NonRobust, Robust},
mutability::{Exclusive, Interior},
niche::{WithNiche, WithoutNiche},
size::{self, Gt, MetaSized, NulTerminated, Sized as SpecSized, SliceLike, Zero},
};
use static_assertions::assert_impl_all;
pub trait Projection {
type Kita<'a>
where
Self: 'a;
}
impl Projection for c_void {
type Kita<'a>
= &'a u8
where
Self: 'a;
}
pub trait CTypeProjection {
type CType;
}
impl CTypeProjection for u8 {
type CType = u8;
}
impl<T: CTypeProjection> CTypeProjection for UnsafeCell<T> {
type CType = T::CType;
}
#[derive(RustSpec)]
pub struct ParamReprCZst<T: ?Sized> {
pub a: (),
pub b: T,
}
#[derive(RustSpec)]
pub struct NulTerminatedTail {
pub prefix: u32,
pub tail: CStr,
}
#[test]
fn nul_terminated_tail_classification() {
assert_impl_all!(NulTerminatedTail: RustSpec<Size = NulTerminated>);
}
#[derive(RustSpec)]
pub struct WithGat1<'b>(pub <c_void as Projection>::Kita<'b>)
where
for<'d> c_void: Projection,
Self: 'b;
#[derive(RustSpec)]
#[repr(C)]
pub struct WithGat2<'b>(pub <u8 as Projection>::Kita<'b>)
where
for<'d> u8: Projection,
Self: 'b;
#[derive(RustSpec)]
#[repr(transparent)]
pub struct Custom2View<'_dšč, 'a>(pub <&'a i8 as Projection>::Kita<'_dšč>)
where
Self: '_dšč,
for<'_dummy> &'a i8: Projection;
#[derive(RustSpec)]
#[repr(transparent)]
pub struct CounterData(<usize as CTypeProjection>::CType)
where
for<'__dummy> usize: CTypeProjection;
#[derive(RustSpec)]
#[repr(C)]
pub struct OpaqueData(<usize as CTypeProjection>::CType)
where
for<'__dummy> usize: CTypeProjection;
#[derive(RustSpec)]
struct Empty;
#[derive(RustSpec)]
pub struct RustStruct {
pub value: u8,
}
#[derive(RustSpec)]
pub struct NonRobustRustRepr {
pub value: bool,
}
#[derive(RustSpec)]
#[repr(C)]
struct ReprCStruct {
value: u8,
}
#[derive(RustSpec)]
#[repr(C)]
struct ReprCProjectionCTypeFields {
first: <UnsafeCell<u8> as CTypeProjection>::CType,
second: <u8 as CTypeProjection>::CType,
}
#[derive(RustSpec)]
pub struct InteriorWrapper {
_left: UnsafeCell<u8>,
pub right: UnsafeCell<u16>,
}
#[derive(RustSpec)]
pub struct MixedMutability {
pub cell: UnsafeCell<u8>,
pub value: u8,
}
#[derive(RustSpec)]
pub struct Wrapper<T> {
pub value: T,
}
#[derive(RustSpec)]
#[repr(C)]
struct Pair<T, U> {
first: T,
second: U,
}
#[derive(RustSpec)]
pub struct SingletonWithNiche(pub NonZeroU8);
#[derive(RustSpec)]
#[repr(transparent)]
struct TransparentWithNiche(NonZeroU8);
#[derive(RustSpec)]
#[repr(transparent)]
struct TransparentWithMultipleFields((), NonZeroU8);
#[derive(RustSpec)]
#[repr(transparent)]
struct TransparentZstStruct;
struct NotRustSpec;
#[derive(RustSpec)]
#[repr(C)]
struct RawPointer<T> {
pointer: *mut T,
}
#[derive(RustSpec)]
#[repr(transparent)]
struct Bytes([u8]);
#[derive(RustSpec)]
pub struct Packet {
pub tag: NonZeroU8,
pub payload: [u8],
}
#[derive(RustSpec)]
pub struct TuplePacket(pub NonZeroU8, pub [u8]);
#[derive(RustSpec)]
#[repr(transparent)]
pub struct TransparentSlice<T>([T]);
#[derive(RustSpec)]
pub struct NoDropStruct(pub u8);
#[derive(RustSpec)]
#[rust_spec(custom_drop)]
pub struct CustomDropStruct(pub u8);
impl Drop for CustomDropStruct {
fn drop(&mut self) {}
}
#[derive(RustSpec)]
pub struct InnerDropStruct(pub CustomDropStruct);
#[derive(RustSpec)]
#[rust_spec(custom_drop)]
pub struct CustomAndInnerDropStruct(pub CustomDropStruct);
impl Drop for CustomAndInnerDropStruct {
fn drop(&mut self) {}
}
#[derive(RustSpec)]
#[rust_spec(custom_drop)]
pub struct CustomWithInnerDropStruct(pub InnerDropStruct);
impl Drop for CustomWithInnerDropStruct {
fn drop(&mut self) {}
}
#[test]
fn struct_drop_classification() {
assert_impl_all!(NoDropStruct: RustSpec<Drop = NoDrop>);
assert_impl_all!(CustomDropStruct: RustSpec<Drop = CustomDrop<NoDrop>>);
assert_impl_all!(InnerDropStruct: RustSpec<Drop = AutoDrop>);
assert_impl_all!(CustomAndInnerDropStruct: RustSpec<Drop = CustomDrop<AutoDrop>>);
assert_impl_all!(CustomWithInnerDropStruct: RustSpec<Drop = CustomDrop<AutoDrop>>);
assert_impl_all!(Option<CustomAndInnerDropStruct>: RustSpec<Drop = AutoDrop>);
assert_impl_all!((CustomDropStruct, CustomDropStruct): RustSpec<Drop = AutoDrop>);
assert_impl_all!(Box<u8>: RustSpec<Drop = CustomDrop<NoDrop>>);
assert_impl_all!(Box<CustomDropStruct>: RustSpec<Drop = CustomDrop<AutoDrop>>);
assert_impl_all!(Box<CustomAndInnerDropStruct>: RustSpec<Drop = CustomDrop<AutoDrop>>);
assert_impl_all!(Vec<u8>: RustSpec<Drop = CustomDrop<NoDrop>>);
assert_impl_all!(Vec<CustomDropStruct>: RustSpec<Drop = CustomDrop<AutoDrop>>);
}
fn assert_rust_spec<T: RustSpec + ?Sized>() {}
fn a_slice_of_any_rust_spec_type_is_rust_spec<T: RustSpec>()
where
rust_spec::drop::NoDrop: Add<T::Drop>,
{
assert_rust_spec::<[T]>();
}
fn a_transparent_slice_wrapper_of_any_rust_spec_type_is_rust_spec<T: RustSpec>()
where
WithoutNiche: Add<T::Niche>,
rust_spec::drop::NoDrop: Add<T::Drop>,
rust_spec::drop::NoDrop: Add<<rust_spec::drop::NoDrop as Add<T::Drop>>::Output>,
{
assert_rust_spec::<TransparentSlice<T>>();
}
#[test]
fn generic_slice_classification() {
a_slice_of_any_rust_spec_type_is_rust_spec::<u8>();
a_transparent_slice_wrapper_of_any_rust_spec_type_is_rust_spec::<u8>();
}
#[test]
fn struct_classification() {
assert_impl_all!(ParamReprCZst<()>:
RustSpec<
Layout = Unstable,
Size = SpecSized<Zero>,
Alignment = rust_spec::One,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(ParamReprCZst<UnsafeCell<NonZeroU8>>:
RustSpec<
Layout = Unstable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = NonRobust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(ParamReprCZst<u8>:
RustSpec<
Layout = Unstable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(SingletonWithNiche:
RustSpec<
Layout = Unstable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = NonRobust,
Niche = WithNiche<Unstable>,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(TransparentWithNiche:
RustSpec<
Layout = Stable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = NonRobust,
Niche = WithNiche<Stable>,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(TransparentWithMultipleFields:
RustSpec<
Layout = Stable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = NonRobust,
Niche = WithNiche<Unstable>,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(TransparentZstStruct:
RustSpec<
Layout = Stable,
Size = SpecSized<Zero>,
Alignment = rust_spec::One,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(Empty:
RustSpec<
Layout = Unstable,
Size = SpecSized<Zero>,
Alignment = rust_spec::One,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(RustStruct:
RustSpec<
Layout = Unstable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(NonRobustRustRepr:
RustSpec<
Layout = Unstable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = NonRobust,
Niche = WithNiche<Unstable>,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(ReprCStruct:
RustSpec<
Layout = Stable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(ReprCProjectionCTypeFields:
RustSpec<
Layout = Stable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(InteriorWrapper:
RustSpec<
Layout = Unstable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::Gt<rust_spec::One>,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(MixedMutability:
RustSpec<
Layout = Unstable,
Size = SpecSized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(Wrapper<u8>:
RustSpec<
Layout = Unstable,
Size = size::Sized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(Wrapper<UnsafeCell<u8>>:
RustSpec<
Layout = Unstable,
Size = size::Sized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Interior,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(Pair<u8, StdNonZero<u8>>:
RustSpec<
Layout = Stable,
Size = size::Sized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = NonRobust,
Niche = WithNiche<Unstable>,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(Pair<bool, u8>:
RustSpec<
Layout = Stable,
Size = size::Sized<Gt<Zero>>,
Alignment = rust_spec::One,
Trap = NonRobust,
Niche = WithNiche<Unstable>,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(RawPointer<NotRustSpec>:
RustSpec<
Layout = Stable,
Size = size::Sized<Gt<Zero>>,
Alignment = <usize as RustSpec>::Alignment,
Trap = Robust,
Niche = WithoutNiche,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
}
#[test]
fn struct_wide_classification() {
assert_impl_all!(Bytes:
RustSpec<
Layout = Stable,
Size = MetaSized<SliceLike>,
Alignment = rust_spec::One,
Trap = Robust,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(Packet:
RustSpec<
Layout = Unstable,
Size = MetaSized<SliceLike>,
Alignment = rust_spec::One,
Trap = NonRobust,
Niche = WithNiche<Unstable>,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
assert_impl_all!(TuplePacket:
RustSpec<
Layout = Unstable,
Size = MetaSized<SliceLike>,
Alignment = rust_spec::One,
Trap = NonRobust,
Niche = WithNiche<Unstable>,
Mutability = Exclusive,
__IndirectTrap = Robust,
>,
);
}