From c8cc4b5f7fb0c2f5e5c3cb6d465810e47294e665 Mon Sep 17 00:00:00 2001 From: Pierre Avital Date: Wed, 31 Jul 2024 11:56:51 +0200 Subject: [PATCH 1/3] v36.1.1 --- CHANGELOG.md | 24 +++++++ Cargo.toml | 8 +-- stabby-abi/src/stable_impls/mod.rs | 101 +++++++++++++++++----------- stabby-abi/src/typenum2/unsigned.rs | 40 +++++++++-- 4 files changed, 122 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 858ec9c..5f570cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,27 @@ +# 36.1.1 (api=2.0.0, abi=2.0.0) +`36.1.1` is the sum of all the previous release candidates. Here's a recap! +- `#[stabby::stabby]` can now understand when a type refers to itself to avoid forming proof cycles. +- `stabby::collections::arc_btree`'s types are now ABI-stable! +- Add the `#[stabby::vt_attr(_)]` sub-attribute to `#[stabby::stabby]` on traits, letting you place custom attributes on the v-tables generated for a trait. +- Add support for `core::ffi::c_void`. +- FIx single-niche evaluation for structures. +- Add support for `#[repr(transparent)]` and `#[repr(align(n))]` in `#[stabby::stabby]` structs up to n=64kiB. +- Added more constructors (such as `FromIterator`) for `BoxedSlice` and `ArcSlice`. +- Added support for more niche platforms. +- BREAKING CHANGES: Mostly due to a large rework of allocations. + - The in-place constructors for `Box` and `Arc` now require the initializer function to return a result, yielding the uninitialized allocation if allocation succeeded but initialization reported a failure. + - `serde` and `libc` features are no longer part of the default features set. + - `RustAlloc` is the new default allocator of `stabby`: this allocator is a simple pointer to a v-table allowing cross-ffi use of Rust's `alloc::GlobalAlloc`. + - This allocator is global, thread-safe, and guaranteed to work properly with pointers passed across the FFI. + - Benchmarks indicate that performance between `RustAlloc` and `LibcAlloc` is equivalent. + - However, it is non-zero-sized, and therefore makes types that don't always shove it into their `AllocPrefix` are slightly bigger when using `RustAlloc` rather than `LibcAlloc`. + - The reason for this change is that `LibcAlloc` isn't available on certain platforms, whereas `RustAlloc` is available on any platform supported by Rust. Importantly, the `wasm32` architecture was unsupported until now. + - The `libc_alloc` module was replaced by the `allocators` module to improve readability. + - While the previous `IAlloc` version was fine to interface with `libc::malloc`'s API, it actually had a few big holes that required patching for custom allocators to be able to do interesting stuff. + - This was unearthed by implementing `RustAlloc` + - The `AllocPrefix`'s location relative to prefixed allocations (such as those used by all of `stabby`'s container types) has changed for types with alignments greater than pointer-size. + - The prefix was previously placed as if the allocation held `Tuple2`, meaning that for larger alignments, there could be padding between the prefix and the pointed value. + # 36.1.1-rc8 (api=2.0.0, abi=2.0.0) - Improve `DefaultAllocator` handling diff --git a/Cargo.toml b/Cargo.toml index a2d17c9..4f21d1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,12 +33,12 @@ license = " EPL-2.0 OR Apache-2.0" categories = ["development-tools::ffi", "no-std::no-alloc"] repository = "https://github.com/ZettaScaleLabs/stabby" readme = "stabby/README.md" -version = "36.1.1-rc8" # Track +version = "36.1.1" # Track [workspace.dependencies] -stabby-macros = { path = "./stabby-macros/", version = "36.1.1-rc8", default-features = false } # Track -stabby-abi = { path = "./stabby-abi/", version = "36.1.1-rc8", default-features = false } # Track -stabby = { path = "./stabby/", version = "36.1.1-rc8", default-features = false } # Track +stabby-macros = { path = "./stabby-macros/", version = "36.1.1", default-features = false } # Track +stabby-abi = { path = "./stabby-abi/", version = "36.1.1", default-features = false } # Track +stabby = { path = "./stabby/", version = "36.1.1", default-features = false } # Track abi_stable = "0.11.0" libc = "0.2" diff --git a/stabby-abi/src/stable_impls/mod.rs b/stabby-abi/src/stable_impls/mod.rs index c1dd063..a60dbcf 100644 --- a/stabby-abi/src/stable_impls/mod.rs +++ b/stabby-abi/src/stable_impls/mod.rs @@ -12,6 +12,8 @@ // Pierre Avital, // +use unsigned::{Bool, IBitBase}; + use crate::{str::Str, *}; macro_rules! same_as { @@ -35,6 +37,21 @@ macro_rules! same_as { }; } +macro_rules! expr_to_type { + ($e: expr) => { + as IBitBase>::_ATernary< + U8, + as IBitBase>::_ATernary< + U4, + as IBitBase>::_ATernary< + U2, + as IBitBase>::_ATernary, + >, + >, + > + }; +} + #[allow(dead_code)] const ARCH: &[u8] = _ARCH; #[cfg(target_arch = "aarch64")] @@ -274,12 +291,13 @@ unsafe impl IStable for bool { type Size = U1; type ForbiddenValues = crate::istable::ForbiddenRange; type UnusedBits = End; - type HasExactlyOneNiche = B0; + type HasExactlyOneNiche = Saturator; type ContainsIndirections = B0; #[cfg(feature = "experimental-ctypes")] type CType = ::AsUint; primitive_report!("bool"); } +check!(bool); // SAFETY: Automatic checks verify this. unsafe impl IStable for u8 { @@ -360,7 +378,7 @@ unsafe impl IStable for core::num::NonZeroU32 { unsafe impl IStable for u64 { type UnusedBits = End; type ForbiddenValues = End; - type Align = U8; + type Align = expr_to_type!(core::mem::align_of::()); type Size = U8; type HasExactlyOneNiche = B0; type ContainsIndirections = B0; @@ -373,7 +391,7 @@ check!(u64); unsafe impl IStable for core::num::NonZeroU64 { type UnusedBits = End; type ForbiddenValues = nz_holes!(U0, U1, U2, U3, U4, U5, U6, U7); - type Align = U8; + type Align = expr_to_type!(core::mem::align_of::()); type Size = U8; type HasExactlyOneNiche = B1; type ContainsIndirections = B0; @@ -388,47 +406,28 @@ unsafe impl IStable for u128 { type ForbiddenValues = End; type Size = U16; type HasExactlyOneNiche = B0; - - #[rustversion::before(1.77)] - #[cfg(not(target_arch = "aarch64"))] - type Align = U8; - #[rustversion::before(1.77)] - #[cfg(target_arch = "aarch64")] - type Align = U16; - #[rustversion::since(1.77)] - #[cfg(not(target_arch = "wasm32"))] - type Align = U16; - #[rustversion::since(1.77)] - #[cfg(target_arch = "wasm32")] - type Align = U8; + type Align = expr_to_type!(core::mem::align_of::()); type ContainsIndirections = B0; #[cfg(feature = "experimental-ctypes")] type CType = ::AsUint; - #[rustversion::before(1.77)] - #[cfg(not(target_arch = "aarch64"))] - primitive_report!("u128(8)"); - #[rustversion::before(1.77)] - #[cfg(target_arch = "aarch64")] - primitive_report!("u128(16)"); - #[rustversion::since(1.77)] - #[cfg(not(target_arch = "wasm32"))] - primitive_report!("u128(16)"); - #[rustversion::since(1.77)] - #[cfg(target_arch = "wasm32")] - primitive_report!("u128(8)"); + primitive_report!(if core::mem::align_of::() == 8 { + "u128(8)" + } else { + "u128(16)" + }); } check!(u128); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::num::NonZeroU128 { + type Size = expr_to_type!(core::mem::size_of::()); + type Align = expr_to_type!(core::mem::align_of::()); type UnusedBits = End; type ForbiddenValues = nz_holes!(U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15); - type Size = U16; type HasExactlyOneNiche = B1; - type Align = ::Align; #[cfg(feature = "experimental-ctypes")] type CType = ::AsUint; type ContainsIndirections = B0; @@ -437,14 +436,15 @@ unsafe impl IStable for core::num::NonZeroU128 { // SAFETY: Automatic checks verify this. unsafe impl IStable for usize { - #[cfg(target_pointer_width = "64")] - same_as!(u64, "usize"); - #[cfg(target_pointer_width = "32")] - same_as!(u32, "usize"); - #[cfg(target_pointer_width = "16")] - same_as!(u16, "usize"); + type Size = expr_to_type!(core::mem::size_of::()); + type Align = expr_to_type!(core::mem::align_of::()); type HasExactlyOneNiche = B0; type ContainsIndirections = B0; + type ForbiddenValues = End; + type UnusedBits = End; + #[cfg(feature = "experimental-ctypes")] + type CType = usize; + primitive_report!("usize"); } check!(usize); @@ -459,6 +459,7 @@ unsafe impl IStable for core::num::NonZeroUsize { type HasExactlyOneNiche = B1; type ContainsIndirections = B0; } +check!(core::num::NonZeroUsize); // SAFETY: Automatic checks verify this. unsafe impl IStable for i8 { @@ -579,69 +580,89 @@ unsafe impl IStable for core::sync::atomic::AtomicPtr { // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicBool { same_as!(bool, "core::sync::atomic::AtomicBool"); - type HasExactlyOneNiche = B0; + type HasExactlyOneNiche = Saturator; type ContainsIndirections = B0; } +check!(core::sync::atomic::AtomicBool); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicI8 { same_as!(i8, "core::sync::atomic::AtomicI8"); type HasExactlyOneNiche = B0; type ContainsIndirections = B0; } +check!(core::sync::atomic::AtomicI8); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicI16 { same_as!(i16, "core::sync::atomic::AtomicI16"); type HasExactlyOneNiche = B0; type ContainsIndirections = B0; } +check!(core::sync::atomic::AtomicI16); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicI32 { same_as!(i32, "core::sync::atomic::AtomicI32"); type HasExactlyOneNiche = B0; type ContainsIndirections = B0; } +check!(core::sync::atomic::AtomicI32); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicI64 { - same_as!(i64, "core::sync::atomic::AtomicI64"); + type Size = U8; + type Align = expr_to_type!(core::mem::align_of::()); + type ForbiddenValues = End; + type UnusedBits = End; type HasExactlyOneNiche = B0; type ContainsIndirections = B0; + #[cfg(feature = "experimental-ctypes")] + type CType = ::AsUint; + primitive_report!("core::sync::atomic::AtomicI64"); } +check!(core::sync::atomic::AtomicI64); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicIsize { same_as!(isize, "core::sync::atomic::AtomicIsize"); type HasExactlyOneNiche = B0; type ContainsIndirections = B0; } +check!(core::sync::atomic::AtomicIsize); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicU8 { same_as!(u8, "core::sync::atomic::AtomicU8"); type HasExactlyOneNiche = B0; type ContainsIndirections = B0; } +check!(core::sync::atomic::AtomicU8); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicU16 { same_as!(u16, "core::sync::atomic::AtomicU16"); type HasExactlyOneNiche = B0; type ContainsIndirections = B0; } +check!(core::sync::atomic::AtomicU16); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicU32 { same_as!(u32, "core::sync::atomic::AtomicU32"); type HasExactlyOneNiche = B0; type ContainsIndirections = B0; } +check!(core::sync::atomic::AtomicU32); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicU64 { - same_as!(u64, "core::sync::atomic::AtomicU64"); + same_as!( + core::sync::atomic::AtomicI64, + "core::sync::atomic::AtomicU64" + ); type HasExactlyOneNiche = B0; type ContainsIndirections = B0; } +check!(core::sync::atomic::AtomicU64); // SAFETY: Automatic checks verify this. unsafe impl IStable for core::sync::atomic::AtomicUsize { same_as!(usize, "core::sync::atomic::AtomicUsize"); type HasExactlyOneNiche = B0; type ContainsIndirections = B0; } +check!(core::sync::atomic::AtomicUsize); // SAFETY: Automatic checks verify this. unsafe impl IStable for &T { same_as!(core::num::NonZeroUsize, "&", T); @@ -933,7 +954,7 @@ macro_rules! sliceimpl { type Size = ::Mul<$size>; type Align = T::Align; type ForbiddenValues = <<$size as Unsigned>::Equal as Bit>::FvTernary; - type UnusedBits = <<$size as Unsigned>::Equal as Bit>::UbTernary; + type UnusedBits = <<$size as Unsigned>::Equal as Bit>::BmTernary; type HasExactlyOneNiche = <<$size as Unsigned>::Equal as Bit>::SaddTernary< B0, <<$size as Unsigned>::Equal as Bit>::SaddTernary, diff --git a/stabby-abi/src/typenum2/unsigned.rs b/stabby-abi/src/typenum2/unsigned.rs index 5f6cc77..160b965 100644 --- a/stabby-abi/src/typenum2/unsigned.rs +++ b/stabby-abi/src/typenum2/unsigned.rs @@ -82,8 +82,6 @@ pub trait IBitBase { /// Support for [`IBit`] type _SfvTernary: ISingleForbiddenValue; /// Support for [`IBit`] - type _UbTernary: IBitMask; - /// Support for [`IBit`] type _SaddTernary: ISaturatingAdd; /// Support for [`IBit`] type _StabTernary: IStable; @@ -110,7 +108,6 @@ impl IBitBase for B0 { type _PTernary = B; type _FvTernary = B; type _SfvTernary = B; - type _UbTernary = B; type _SaddTernary = B; type _StabTernary = B; type _ATernary = B; @@ -133,13 +130,45 @@ impl IBitBase for B1 { type _PTernary = A; type _FvTernary = A; type _SfvTernary = A; - type _UbTernary = A; type _SaddTernary = A; type _StabTernary = A; type _ATernary = A; type _Padding = PadByte; type AsForbiddenValue = End; } +/// Equivalent to `B0` and `B1`, but can be constructed with a `const` expression. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub struct Bool; +macro_rules! same_as_bitbase { + ($src: ty) => { + const _BOOL: bool = <$src as IBitBase>::_BOOL; + type _And = <$src as IBitBase>::_And; + type _Or = <$src as IBitBase>::_Or; + type _Not = <$src as IBitBase>::_Not; + type _Ternary = <$src as IBitBase>::_Ternary; + type _UTernary = <$src as IBitBase>::_UTernary; + type _NzTernary = <$src as IBitBase>::_NzTernary; + type _BTernary = <$src as IBitBase>::_BTernary; + type _BmTernary = <$src as IBitBase>::_BmTernary; + type _PTernary = <$src as IBitBase>::_PTernary; + type _FvTernary = + <$src as IBitBase>::_FvTernary; + type _SfvTernary = + <$src as IBitBase>::_SfvTernary; + type _SaddTernary = + <$src as IBitBase>::_SaddTernary; + type _StabTernary = <$src as IBitBase>::_StabTernary; + type _ATernary = <$src as IBitBase>::_ATernary; + type _Padding = <$src as IBitBase>::_Padding; + type AsForbiddenValue = <$src as IBitBase>::AsForbiddenValue; + }; +} +impl IBitBase for Bool { + same_as_bitbase!(B0); +} +impl IBitBase for Bool { + same_as_bitbase!(B1); +} /// A boolean. [`B0`] and [`B1`] are the canonical members of this type-class pub trait IBit: IBitBase { /// Converts from type to value @@ -165,8 +194,6 @@ pub trait IBit: IBitBase { /// Self ? A : B, preserving bounds. type FvTernary: IForbiddenValues; /// Self ? A : B, preserving bounds. - type UbTernary: IBitMask; - /// Self ? A : B, preserving bounds. type SaddTernary: ISaturatingAdd; /// Self ? A : B, preserving bounds. type StabTernary: IStable; @@ -197,7 +224,6 @@ impl IBit for Bit { type BmTernary = Self::_BmTernary; type PTernary = Self::_PTernary; type FvTernary = Self::_FvTernary; - type UbTernary = Self::_UbTernary; type SaddTernary = Self::_SaddTernary; type StabTernary = Self::_StabTernary; type Nand = as IBitBase>::_Not; From 7935dbdb31dded105541d968bc7f1f4fa5693d19 Mon Sep 17 00:00:00 2001 From: Pierre Avital Date: Wed, 31 Jul 2024 12:10:14 +0200 Subject: [PATCH 2/3] Update CI to sample alternative archs --- .github/workflows/ci.yml | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ddded2..8cc6086 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,6 +80,54 @@ jobs: with: command: clean + check-wasm: + name: Run wasm checks on ${{ matrix.os }} + runs-on: [self-hosted, "${{ matrix.os }}"] + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04] + steps: + - uses: actions/checkout@v2 + - name: Install Rust toolchain 1.72 + uses: actions-rs/toolchain@v1 + with: + profile: minimal + target: wasm32-unknown-unknown + - name: Check + uses: actions-rs/cargo@v1 + with: + command: check + args: -p stabby + - name: Clean artifacts + uses: actions-rs/cargo@v1 + with: + command: clean + + check-32bits: + name: Run 32bits checks on ${{ matrix.os }} + runs-on: [self-hosted, "${{ matrix.os }}"] + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04] + steps: + - uses: actions/checkout@v2 + - name: Install Rust toolchain 1.72 + uses: actions-rs/toolchain@v1 + with: + profile: minimal + target: i686-unknown-linux-gnu + - name: Check + uses: actions-rs/cargo@v1 + with: + command: check + args: -p stabby + - name: Clean artifacts + uses: actions-rs/cargo@v1 + with: + command: clean + test: name: Run tests on ${{ matrix.os }} runs-on: [self-hosted, "${{ matrix.os }}"] From 70d88abdae1fdc95a766ab7e8974003ff1ace587 Mon Sep 17 00:00:00 2001 From: Pierre Avital Date: Wed, 31 Jul 2024 14:30:42 +0200 Subject: [PATCH 3/3] fix lints --- stabby-abi/src/stable_impls/mod.rs | 3 --- stabby/build.rs | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 stabby/build.rs diff --git a/stabby-abi/src/stable_impls/mod.rs b/stabby-abi/src/stable_impls/mod.rs index a60dbcf..a46d1b4 100644 --- a/stabby-abi/src/stable_impls/mod.rs +++ b/stabby-abi/src/stable_impls/mod.rs @@ -106,8 +106,6 @@ const _ARCH: &[u8] = b"wasm64"; const _ARCH: &[u8] = b"x86"; #[cfg(target_arch = "x86_64")] const _ARCH: &[u8] = b"x86_64"; -#[cfg(target_arch = "xtensa")] -const _ARCH: &[u8] = b"xtensa"; #[cfg(not(any( target_arch = "aarch64", target_arch = "arm", @@ -135,7 +133,6 @@ const _ARCH: &[u8] = b"xtensa"; target_arch = "wasm64", target_arch = "x86", target_arch = "x86_64", - target_arch = "xtensa" )))] const _ARCH: &[u8] = b"unknown_arch"; diff --git a/stabby/build.rs b/stabby/build.rs new file mode 100644 index 0000000..5f9d678 --- /dev/null +++ b/stabby/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!(r#"cargo:rustc-check-cfg=cfg(stabby_unsafe_wakers, values(none(), "true", "false"))"#); +}