Skip to content

Commit

Permalink
copyable!, many more impls for Borrowable
Browse files Browse the repository at this point in the history
prep-work for `#[derive()]`ing value-borrowable `struct`s
  • Loading branch information
MaulingMonkey committed Feb 15, 2024
1 parent bab84e7 commit ef5b820
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#[path = "zst_callbacks/_zst_callbacks.rs"] pub mod ZstCallbacks;
}

#[macro_use] mod macros; #[doc(hidden)] pub use macros::_valrow_macros_prelude;
mod borrowable; pub use crate::borrowable::*;
mod valrow; pub use crate::valrow::*;
mod valrow_mut; pub use crate::valrow_mut::*;
26 changes: 20 additions & 6 deletions src/borrowable.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
use core::ptr::NonNull;
#[cfg(doc)] use core::alloc::Layout;



/// A type that is borrowable by value.
///
/// ### Safety
/// By implementing this trait, you assert that it's safe and sound for a single instance of `Self` to exist at multiple addresses simultaneously.
/// This might exclude [`Box`, `Vec`, other users of `Unique`](<https://github.com/rust-lang/unsafe-code-guidelines/issues/326>), and types directly containing those types by value.
/// Additionally, `Self` and <code>Self::[Abi](Self::Abi)</code> must be ABI compatible.
/// Additionally, `Self` and <code>Self::[Abi](Self::Abi)</code> must be ABI compatible:
/// * Ideally, `#[repr(transparent)]`-compatible, so by-value borrows can substitute for owned values at FFI boundaries.
/// * At absolute minimum, `#[repr(C)]`-compatible (same [`Layout`], same niches, same mutability, same lifetimes, ...)
///
/// Do not implement this on types with direct interior mutability.
/// The copies of the "single" instance will decohere.
Expand Down Expand Up @@ -107,15 +114,22 @@ pub unsafe trait Borrowable

// TODO: make a `#[derive(BorrowableZst)]` that verifies the type is a ZST?
// TODO: make a `#[derive(Borrowable)]` that verifies all members are `Borrowable`?
unsafe impl Borrowable for () { type Abi = (); }
// TODO: add many more core/alloc/std types to improve the usability of said derive?

#[cfg(xxx)] // ❌: ABI should be more permissive for exclusive borrows
unsafe impl<'a, T: ?Sized> Borrowable for &'a mut T { type Abi = NonNull<T>; }
unsafe impl<'a, T: ?Sized> Borrowable for &'a T { type Abi = &'a T; }
unsafe impl<T: ?Sized> Borrowable for *const T { type Abi = *const T; }
unsafe impl<T: ?Sized> Borrowable for *mut T { type Abi = *mut T; }
unsafe impl<T: ?Sized> Borrowable for NonNull<T> { type Abi = NonNull<T>; }

#[cfg(feature = "alloc")] const _ : () = {
use core::ptr::NonNull;
#[cfg(xxx_borrowable_box)]
unsafe impl<T> Borrowable for alloc::boxed ::Box<T> { type Abi = NonNull<T>; } // ❌ UB? See try_to_break_box_valrows below.
unsafe impl<T> Borrowable for alloc::rc ::Rc <T> { type Abi = NonNull<T>; }
unsafe impl<T> Borrowable for alloc::sync ::Arc<T> { type Abi = NonNull<T>; }
unsafe impl<T: ?Sized> Borrowable for alloc::boxed ::Box <T> { type Abi = NonNull<T>; } // ❌ UB? See try_to_break_box_valrows below.
unsafe impl<T: ?Sized> Borrowable for alloc::rc ::Rc <T> { type Abi = NonNull<T>; }
unsafe impl<T: ?Sized> Borrowable for alloc::rc ::Weak<T> { type Abi = NonNull<T>; }
unsafe impl<T: ?Sized> Borrowable for alloc::sync ::Arc <T> { type Abi = NonNull<T>; }
unsafe impl<T: ?Sized> Borrowable for alloc::sync ::Weak<T> { type Abi = NonNull<T>; }
};


Expand Down
48 changes: 48 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use core::num::*;
#[cfg(doc)] use core::ops::*;



/// <code>copyable!\([u8], [u16], ...\)</code> &mdash; implements the appropriate traits for types that should be value-borrowed by [`Copy`].
///
/// Do not use on types with direct interior mutability... if any ever exist.
/// While no undefined behavior should result, the results will be suprising and counterintuitive.
///
/// ### Examples
/// ```
/// # use valrow::*;
/// // As used by the crate itself:
/// # #[cfg(xxx)] {
/// copyable!(());
/// copyable!(bool, char, f32, f64);
/// copyable!(i8, i16, i32, i64, i128, isize);
/// copyable!(u8, u16, u32, u64, u128, usize);
/// copyable!(NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize);
/// copyable!(NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize);
/// # }
/// ```
///
#[macro_export] macro_rules! copyable { ( $($ty:ty),* $(,)? ) => { const _ : () = {
use $crate::_valrow_macros_prelude::*;
$(
static_assert::copyable::<$ty>();
unsafe impl valrow::Borrowable for $ty { type Abi = $ty; }
)*
};}}

copyable!(());
copyable!(bool, char, f32, f64);
copyable!(i8, i16, i32, i64, i128, isize);
copyable!(u8, u16, u32, u64, u128, usize);
copyable!(NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize);
copyable!(NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize);



#[doc(hidden)] pub mod _valrow_macros_prelude {
pub use crate as valrow;
pub use ::core;
pub mod static_assert {
pub const fn copyable<T: Copy>() {}
}
}

0 comments on commit ef5b820

Please sign in to comment.