Skip to content

Commit

Permalink
Add necessary support for safer_ffi integration
Browse files Browse the repository at this point in the history
  • Loading branch information
p-avital committed Jun 25, 2024
1 parent eaab145 commit 090178e
Show file tree
Hide file tree
Showing 27 changed files with 218 additions and 236 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# 6.1.1
- Add support for multi-fields variants in `repr(C, u*)` enums.
- Deprecate support for `repr(C)` by deprecating any enum that uses it without also specifying a determinant size.
- Remove `CompilerVersion_X_Y_Z` types and their `CurrentCompilerVersion` type alias: the former were hard to keep up to date and the latter could break your code if you upgraded to a version of the compiler that `stabby` didn't know of.
- Prepare integration of `stabby` and [`safer-ffi`](https://crates.io/crates/safer-ffi) by adding `CType` and `is_invalid` to `IStable`.

# 5.1.0
Expand Down
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,13 @@ 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 = "6.1.1"

[workspace.dependencies]
stabby-macros = { path = "./stabby-macros/", version = "6.1.1", default-features = false }
stabby-abi = { path = "./stabby-abi/", version = "6.1.1", default-features = false }
stabby = { path = "./stabby/", version = "6.1.1", default-features = false }

abi_stable = "0.11.2"
criterion = "0.5.1"
lazy_static = "1.4.0"
Expand Down
5 changes: 3 additions & 2 deletions stabby-abi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

[package]
name = "stabby-abi"
version = "5.1.0"
version = { workspace = true }
edition = "2021"
authors = { workspace = true }
license = { workspace = true }
Expand All @@ -39,7 +39,8 @@ abi_stable-channels = ["abi_stable", "abi_stable/channels"]
# stabby_unsafe_wakers = [] # stabby_unsafe_wakers is no longer a feature, but a compile option: you can enable them using `RUST_FLAGS='--cfg stabby_unsafe_wakers="true"'`

[dependencies]
stabby-macros = { path = "../stabby-macros/", version = "5.1.0" }
stabby-macros.workspace = true

abi_stable = { workspace = true, optional = true }
libc = { workspace = true, optional = true }
rustversion = { workspace = true }
Expand Down
10 changes: 7 additions & 3 deletions stabby-abi/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ fn typenum_unsigned() -> std::io::Result<()> {
Ok(())
}

fn tuples() -> std::io::Result<()> {
fn tuples(max_tuple: usize) -> std::io::Result<()> {
let filename = PathBuf::from(std::env::var_os("OUT_DIR").unwrap()).join("tuples.rs");
let mut file = BufWriter::new(File::create(filename).unwrap());
for i in 0..128 {
for i in 0..=max_tuple {
writeln!(
file,
r##"/// An ABI stable tuple of {i} elements.
Expand Down Expand Up @@ -103,7 +103,11 @@ impl<{generics}> From<Tuple{i}<{generics}>> for ({generics}) {{

fn main() {
typenum_unsigned().unwrap();
tuples().unwrap();
println!("cargo:rustc-check-cfg=cfg(stabby_max_tuple, values(any()))");
let max_tuple = std::env::var("CARGO_CFG_STABBY_MAX_TUPLE")
.map_or(32, |s| s.parse().unwrap_or(32))
.max(10);
tuples(max_tuple).unwrap();
println!("cargo:rustc-check-cfg=cfg(stabby_nightly, values(none()))");
println!(
r#"cargo:rustc-check-cfg=cfg(stabby_check_unreachable, values(none(), "true", "false"))"#
Expand Down
3 changes: 2 additions & 1 deletion stabby-abi/src/alloc/collections/arc_btree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ where
type UnusedBits = <*const T as IStable>::UnusedBits;
type HasExactlyOneNiche = crate::B0;
type ContainsIndirections = crate::B1;
type CType = <*const T as IStable>::CType;
const REPORT: &'static crate::report::TypeReport = &crate::report::TypeReport {
name: crate::str::Str::new("ArcBTreeSet"),
module: crate::str::Str::new("stabby_abi::alloc::collections::arc_btree"),
Expand Down Expand Up @@ -248,7 +249,7 @@ impl<T: Ord + Clone, const REPLACE_ON_INSERT: bool, const SPLIT_LIMIT: usize>
const fn as_ptr(
&self,
) -> *mut ArcBTreeSetNodeInner<T, DefaultAllocator, REPLACE_ON_INSERT, SPLIT_LIMIT> {
unsafe { core::mem::transmute_copy(self) }
unsafe { core::mem::transmute(core::ptr::read(self)) }
}
fn copy_from_ptr(
ptr: *const ArcBTreeSetNodeInner<T, DefaultAllocator, REPLACE_ON_INSERT, SPLIT_LIMIT>,
Expand Down
6 changes: 6 additions & 0 deletions stabby-abi/src/alloc/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,16 @@ impl<T, Alloc: IAlloc> Arc<T, Alloc> {
pub fn downgrade(this: &Self) -> Weak<T, Alloc> {
this.into()
}
#[rustversion::since(1.73)]
/// Returns a reference to the allocator used to construct `this`
pub const fn allocator(this: &Self) -> &Alloc {
unsafe { &this.ptr.prefix().alloc }
}
#[rustversion::before(1.73)]
/// Returns a reference to the allocator used to construct `this`
pub fn allocator(this: &Self) -> &Alloc {
unsafe { &this.ptr.prefix().alloc }
}
}
impl<T, Alloc: IAlloc> Drop for Arc<T, Alloc> {
fn drop(&mut self) {
Expand Down
3 changes: 3 additions & 0 deletions stabby-abi/src/enums/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ unsafe impl IStable for BitDeterminant {
type UnusedBits = Array<U0, U254, End>;
type HasExactlyOneNiche = Saturator;
type ContainsIndirections = B0;
type CType = u8;
primitive_report!("BitDeterminant");
}

Expand Down Expand Up @@ -95,6 +96,7 @@ unsafe impl<Offset, Value, Tail: IStable> IStable for ValueIsErr<Offset, Value,
type UnusedBits = Tail::UnusedBits;
type HasExactlyOneNiche = Tail::HasExactlyOneNiche;
type ContainsIndirections = B0;
type CType = ();
primitive_report!("ValueIsErr");
}
impl<Offset: Unsigned, Value: Unsigned, Tail: IDeterminant + core::fmt::Debug> core::fmt::Debug
Expand Down Expand Up @@ -186,6 +188,7 @@ unsafe impl<Determinant: IStable> IStable for Not<Determinant> {
type UnusedBits = Determinant::UnusedBits;
type HasExactlyOneNiche = Determinant::HasExactlyOneNiche;
type ContainsIndirections = Determinant::ContainsIndirections;
type CType = Determinant::CType;
primitive_report!("Not", Determinant);
}
impl<Determinant: IDeterminant> IDeterminant for Not<Determinant>
Expand Down
2 changes: 1 addition & 1 deletion stabby-abi/src/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ mod stable_waker {
///
/// While this is the only way to guarantee ABI-stability when interacting with futures, this does add
/// a layer of indirection, and cloning this waker will cause an allocation. To bench the performance cost
/// of this wrapper and decide if you want to risk ABI-unstability on wakers, you may use `RUST_FLAGS='--cfg stabby_unsafe_wakers="true"'`, which will turn [`StableWaker`] into a newtype of [`core::task::Waker`].
/// of this wrapper and decide if you want to risk ABI-unstability on wakers, you may use `RUSTFLAGS='--cfg stabby_unsafe_wakers="true"'`, which will turn [`StableWaker`] into a newtype of [`core::task::Waker`].
#[crate::stabby]
pub struct StableWaker<'a, Alloc: IAlloc = crate::alloc::DefaultAllocator> {
waker: StableLike<&'a Waker, &'a ()>,
Expand Down
37 changes: 12 additions & 25 deletions stabby-abi/src/istable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,7 @@ use super::typenum2::*;
use super::unsigned::{IBitBase, NonZero};
use super::{FieldPair, Struct, Union};
use stabby_macros::tyeval;
macro_rules! same_as {
($t: ty) => {
type Align = <$t as IStable>::Align;
type Size = <$t as IStable>::Size;
type UnusedBits = <$t as IStable>::UnusedBits;
type ForbiddenValues = <$t as IStable>::ForbiddenValues;
type HasExactlyOneNiche = <$t as IStable>::HasExactlyOneNiche;
type ContainsIndirections = <$t as IStable>::ContainsIndirections;
const REPORT: &'static TypeReport = <$t as IStable>::REPORT;
const ID: u64 = <$t as IStable>::ID;
};
}

/// A trait to describe the layout of a type, marking it as ABI-stable.
///
/// Every layout is assumed to start at the type's first byte.
Expand All @@ -55,6 +44,8 @@ pub unsafe trait IStable: Sized {
type HasExactlyOneNiche: ISaturatingAdd;
/// Whether or not the type contains indirections (pointers, indices in independent data-structures...)
type ContainsIndirections: Bit;
/// A support mechanism for [`safer-ffi`](https://crates.io/crates/safer-ffi), allowing all [`IStable`] types to also be `safer_ffi::ReprC`
type CType: IStable;
/// A compile-time generated report of the fields of the type, allowing for compatibility inspection.
const REPORT: &'static TypeReport;
/// A stable (and ideally unique) identifier for the type. Often generated using [`crate::report::gen_id`], but can be manually set.
Expand Down Expand Up @@ -132,6 +123,7 @@ unsafe impl<T: IStable> IStable for NotPod<T> {
type ForbiddenValues = T::ForbiddenValues;
type HasExactlyOneNiche = T::HasExactlyOneNiche;
type UnusedBits = T::UnusedBits;
type CType = T::CType;
primitive_report!("NotPod", T);
}

Expand Down Expand Up @@ -196,6 +188,7 @@ unsafe impl<
type UnusedBits = UnusedBits;
type HasExactlyOneNiche = HasExactlyOneNiche;
type ContainsIndirections = B0;
type CType = ();
primitive_report!("NicheExporter");
}

Expand Down Expand Up @@ -393,6 +386,7 @@ unsafe impl<A: IStable, B: IStable> IStable for FieldPair<A, B> {
<AlignedAfter<B, A::Size> as IStable>::HasExactlyOneNiche,
>;
type ContainsIndirections = <A::ContainsIndirections as Bit>::Or<B::ContainsIndirections>;
type CType = ();
primitive_report!("FP");
}
/// Runtime values for [`ISaturatingAdd`]
Expand Down Expand Up @@ -516,27 +510,18 @@ impl<O1: Unsigned, T1, O2: Unsigned, T2, R2: IBitMask> IncludesComputer<(O1, T1,
type Output = End;
}

unsafe impl<A: IStable, B: IStable> IStable for Union<A, B>
where
(Self, tyeval!(A::Align == B::Align)): IStable,
{
same_as!((Self, tyeval!(A::Align == B::Align)));
}
unsafe impl<A: IStable, B: IStable> IStable for (Union<A, B>, B1) {
unsafe impl<A: IStable, B: IStable> IStable for Union<A, B> {
type ForbiddenValues = End;
type UnusedBits = End;
type Size = <A::Size as Unsigned>::Max<B::Size>;
type Align = <A::Align as Alignment>::Max<B::Align>;
type HasExactlyOneNiche = B0;
type ContainsIndirections = <A::ContainsIndirections as Bit>::Or<B::ContainsIndirections>;
type CType = <<Self::Align as PowerOf2>::Divide<Self::Size> as IUnsignedBase>::Array<
<Self::Align as Alignment>::AsUint,
>;
primitive_report!("Union");
}
unsafe impl<A: IStable, B: IStable> IStable for (Union<A, B>, B0)
where
Struct<(Union<A, B>, B1)>: IStable,
{
same_as!(Struct<(Union<A, B>, B1)>);
}

/// Computes a `T`-typed field's layout when it's after `Start` bytes, taking `T`'s alignment into account.
pub struct AlignedAfter<T, Start: Unsigned>(core::marker::PhantomData<(T, Start)>);
Expand All @@ -552,6 +537,7 @@ unsafe impl<T: IStable, Start: Unsigned> IStable for AlignedAfter<T, Start> {
>;
type HasExactlyOneNiche = T::HasExactlyOneNiche;
type ContainsIndirections = T::ContainsIndirections;
type CType = ();
primitive_report!("FP");
}

Expand All @@ -563,5 +549,6 @@ unsafe impl<T: IStable> IStable for Struct<T> {
<<tyeval!(<T::Size as Unsigned>::NextMultipleOf<T::Align> - T::Size) as IUnsignedBase>::PaddingBitMask as IBitMask>::Shift<T::Size>>;
type HasExactlyOneNiche = Saturator;
type ContainsIndirections = T::ContainsIndirections;
type CType = ();
primitive_report!("FP");
}
9 changes: 5 additions & 4 deletions stabby-abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ use core::fmt::{Debug, Display};
pub const fn assert_stable<T: IStable>() {}

/// An ABI-stable tuple.
#[crate::stabby]
#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
pub struct Tuple<A, B>(pub A, pub B);
pub use tuple::Tuple2 as Tuple;

/// Generate the [`IStable::REPORT`] and [`IStable::ID`] fields for an implementation of [`IStable`].
#[macro_export]
Expand Down Expand Up @@ -263,6 +261,7 @@ unsafe impl<T, As: IStable> IStable for StableLike<T, As> {
type UnusedBits = As::UnusedBits;
type HasExactlyOneNiche = As::HasExactlyOneNiche;
type ContainsIndirections = As::ContainsIndirections;
type CType = As::CType;
const ID: u64 = crate::report::gen_id(Self::REPORT);
const REPORT: &'static report::TypeReport = As::REPORT;
}
Expand Down Expand Up @@ -295,6 +294,7 @@ unsafe impl<
type UnusedBits = End;
type HasExactlyOneNiche = HasExactlyOneNiche;
type ContainsIndirections = ContainsIndirections;
type CType = ();
primitive_report!("NoNiches");
}

Expand Down Expand Up @@ -346,6 +346,7 @@ unsafe impl<T: IStable, Cond: IStable> IStable for StableIf<T, Cond> {
type UnusedBits = T::UnusedBits;
type HasExactlyOneNiche = T::HasExactlyOneNiche;
type ContainsIndirections = T::ContainsIndirections;
type CType = T::CType;
const REPORT: &'static report::TypeReport = T::REPORT;
const ID: u64 = crate::report::gen_id(Self::REPORT);
}
Expand Down Expand Up @@ -391,7 +392,7 @@ pub mod slice;
/// ABI-stable strs.
pub mod str;
/// ABI-stable tuples.
pub mod tuples {
pub mod tuple {
include!(concat!(env!("OUT_DIR"), "/tuples.rs"));
}

Expand Down
2 changes: 2 additions & 0 deletions stabby-abi/src/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ macro_rules! define_non_max {
type UnusedBits = <$NonZeroU8 as crate::IStable>::UnusedBits;
type HasExactlyOneNiche = <$NonZeroU8 as crate::IStable>::HasExactlyOneNiche;
type ContainsIndirections = <$NonZeroU8 as crate::IStable>::ContainsIndirections;
type CType = <$NonZeroU8 as crate::IStable>::CType;
const ID: u64 = $crate::report::gen_id(Self::REPORT);
const REPORT: &'static $crate::report::TypeReport = &$crate::report::TypeReport {
name: $crate::str::Str::new(stringify!($NonMaxU8)),
Expand Down Expand Up @@ -139,6 +140,7 @@ macro_rules! define_non_x {
type UnusedBits = <$NonZeroU8 as crate::IStable>::UnusedBits;
type HasExactlyOneNiche = <$NonZeroU8 as crate::IStable>::HasExactlyOneNiche;
type ContainsIndirections = <$NonZeroU8 as crate::IStable>::ContainsIndirections;
type CType = <$NonZeroU8 as crate::IStable>::CType;
const ID: u64 = $crate::report::gen_id(Self::REPORT);
const REPORT: &'static $crate::report::TypeReport = &$crate::report::TypeReport {
name: $crate::str::Str::new(stringify!($NonMaxU8)),
Expand Down
1 change: 1 addition & 0 deletions stabby-abi/src/padding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ unsafe impl<Left: Unsigned, T: IStable> IStable for Padded<Left, T> {
>;
type HasExactlyOneNiche = Saturator;
type ContainsIndirections = T::ContainsIndirections;
type CType = Tuple<<Left::Padding as IStable>::CType, T::CType>;
const REPORT: &'static report::TypeReport = T::REPORT;
const ID: u64 = crate::report::gen_id(Self::REPORT);
}
Expand Down
12 changes: 8 additions & 4 deletions stabby-abi/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ where
<<Ok as IDeterminantProvider<Err>>::NicheExporter as IStable>::ForbiddenValues;
type UnusedBits = <<Tuple<Determinant<Ok, Err>, <Self::Align as Alignment>::AsUint> as IStable>::UnusedBits as IBitMask>::BitOr<<<<Ok as IDeterminantProvider<Err>>::NicheExporter as IStable>::UnusedBits as IBitMask>::Shift<<<Determinant<Ok, Err> as IStable>::Size as Unsigned>::NextMultipleOf<Self::Align>>>;
type HasExactlyOneNiche = B0;
type CType = <Storage<<Self as IStable>::Size, <Self as IStable>::Align> as IStable>::CType;
const REPORT: &'static crate::report::TypeReport = &crate::report::TypeReport {
name: Str::new("Result"),
module: Str::new("stabby_abi::result"),
Expand All @@ -70,10 +71,13 @@ where
};
const ID: u64 = crate::report::gen_id(Self::REPORT);
}

#[stabby::stabby]
struct Storage<Size: Unsigned, Align: Alignment + Alignment> {
inner: <Align::Divide<Size> as IUnsignedBase>::Array<Align::AsUint>,
use seal::Storage;
mod seal {
use super::*;
#[stabby::stabby]
pub struct Storage<Size: Unsigned, Align: Alignment + Alignment> {
inner: <Align::Divide<Size> as IUnsignedBase>::Array<Align::AsUint>,
}
}

impl<Size: Unsigned, Align: Alignment + Alignment> Storage<Size, Align> {
Expand Down
Loading

0 comments on commit 090178e

Please sign in to comment.