Unify/reduce usage of `unsafe`
Since the introduction of `Script` `unsafe` started slowly creeping in as more types with similar semantics were added. The `unsafe` in these cases is just for trivial conversions between various pointer-like types. As such, it's possible to move these into a single macro that takes care of the conversions at one place and avoid repeating the same `unsafe` code in the codebase. This decreases the cost of audits which now only need to happen in `internals`, focuses any changes to happen in that single macro and decreases the chance that we will mess up similarly to the recent `try_into().expect()` issue (but this time with UB rather than panic). The new macro accepts syntax very similar to the already-existing struct declarations with these differences: * The struct MUST NOT have `#[repr(transparent)]` - it's added by the macro * If the struct uses `PhantomData` it must be the first field and the real data must be the second field (to allow unsized types). * The struct must be immediately followed by an impl block containing at least on conversion function. * If the struct has generics the impl block has to use the same names of generics. * The conversion functions don't have bodies (similarly to required trait methods) and have a fixed set of allowed signatures. * Underscore (`_`) must be used in place of the inner type in the conversion function parameters. The existing code can simply call the macro with simple changes and get the same behavior without any direct use of `unsafe`. This change already calls the macro for all relevant existing types. There are still some usages left unrelated to the macro, except one additional conversion in reverse direction on `Script`. It could be moved as well but since it's on a single place so far it's not really required.
This commit is contained in:
parent
d42364bd9d
commit
e8a42d5851
|
@ -308,6 +308,7 @@ pub enum AddressData {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internals::transparent_newtype! {
|
||||||
/// A Bitcoin address.
|
/// A Bitcoin address.
|
||||||
///
|
///
|
||||||
/// ### Parsing addresses
|
/// ### Parsing addresses
|
||||||
|
@ -394,11 +395,15 @@ pub enum AddressData {
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
// The `#[repr(transparent)]` attribute is used to guarantee the layout of the `Address` struct. It
|
// The `#[repr(transparent)]` attribute is used to guarantee the layout of the `Address` struct. It
|
||||||
// is an implementation detail and users should not rely on it in their code.
|
// is an implementation detail and users should not rely on it in their code.
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct Address<V = NetworkChecked>(PhantomData<V>, AddressInner)
|
pub struct Address<V = NetworkChecked>(PhantomData<V>, AddressInner)
|
||||||
where
|
where
|
||||||
V: NetworkValidation;
|
V: NetworkValidation;
|
||||||
|
|
||||||
|
impl<V> Address<V> {
|
||||||
|
fn from_inner_ref(inner: &_) -> &Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
struct DisplayUnchecked<'a, N: NetworkValidation>(&'a Address<N>);
|
struct DisplayUnchecked<'a, N: NetworkValidation>(&'a Address<N>);
|
||||||
|
|
||||||
|
@ -468,7 +473,7 @@ impl<V: NetworkValidation> Address<V> {
|
||||||
|
|
||||||
/// Returns a reference to the address as if it was unchecked.
|
/// Returns a reference to the address as if it was unchecked.
|
||||||
pub fn as_unchecked(&self) -> &Address<NetworkUnchecked> {
|
pub fn as_unchecked(&self) -> &Address<NetworkUnchecked> {
|
||||||
unsafe { &*(self as *const Address<V> as *const Address<NetworkUnchecked>) }
|
Address::from_inner_ref(self.inner())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks the network of this address as unchecked.
|
/// Marks the network of this address as unchecked.
|
||||||
|
@ -803,7 +808,7 @@ impl Address<NetworkUnchecked> {
|
||||||
///
|
///
|
||||||
/// This function is dangerous in case the address is not a valid checked address.
|
/// This function is dangerous in case the address is not a valid checked address.
|
||||||
pub fn assume_checked_ref(&self) -> &Address {
|
pub fn assume_checked_ref(&self) -> &Address {
|
||||||
unsafe { &*(self as *const Address<NetworkUnchecked> as *const Address) }
|
Address::from_inner_ref(self.inner())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parsed addresses do not always have *one* network. The problem is that legacy testnet,
|
/// Parsed addresses do not always have *one* network. The problem is that legacy testnet,
|
||||||
|
|
|
@ -35,33 +35,29 @@ mod primitive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internals::transparent_newtype! {
|
||||||
/// Byte slices that can be in Bitcoin script.
|
/// Byte slices that can be in Bitcoin script.
|
||||||
///
|
///
|
||||||
/// The encoding of Bitcoin script restricts data pushes to be less than 2^32 bytes long.
|
/// The encoding of Bitcoin script restricts data pushes to be less than 2^32 bytes long.
|
||||||
/// This type represents slices that are guaranteed to be within the limit so they can be put in
|
/// This type represents slices that are guaranteed to be within the limit so they can be put in
|
||||||
/// the script safely.
|
/// the script safely.
|
||||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct PushBytes([u8]);
|
pub struct PushBytes([u8]);
|
||||||
|
|
||||||
impl PushBytes {
|
impl PushBytes {
|
||||||
/// Constructs a new `&PushBytes` without checking the length.
|
/// Constructs a new `&PushBytes` without checking the length.
|
||||||
///
|
///
|
||||||
/// The caller is responsible for checking that the length is less than the 2^32.
|
/// The caller is responsible for checking that the length is less than the 2^32.
|
||||||
fn from_slice_unchecked(bytes: &[u8]) -> &Self {
|
fn from_slice_unchecked(bytes: &_) -> &Self;
|
||||||
// SAFETY: The conversion is sound because &[u8] and &PushBytes
|
|
||||||
// have the same layout (because of #[repr(transparent)] on PushBytes).
|
|
||||||
unsafe { &*(bytes as *const [u8] as *const PushBytes) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a new `&mut PushBytes` without checking the length.
|
/// Constructs a new `&mut PushBytes` without checking the length.
|
||||||
///
|
///
|
||||||
/// The caller is responsible for checking that the length is less than the 2^32.
|
/// The caller is responsible for checking that the length is less than the 2^32.
|
||||||
fn from_mut_slice_unchecked(bytes: &mut [u8]) -> &mut Self {
|
fn from_mut_slice_unchecked(bytes: &mut _) -> &mut Self;
|
||||||
// SAFETY: The conversion is sound because &mut [u8] and &mut PushBytes
|
|
||||||
// have the same layout (because of #[repr(transparent)] on PushBytes).
|
|
||||||
unsafe { &mut *(bytes as *mut [u8] as *mut PushBytes) }
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PushBytes {
|
||||||
|
|
||||||
/// Constructs an empty `&PushBytes`.
|
/// Constructs an empty `&PushBytes`.
|
||||||
pub fn empty() -> &'static Self { Self::from_slice_unchecked(&[]) }
|
pub fn empty() -> &'static Self { Self::from_slice_unchecked(&[]) }
|
||||||
|
|
|
@ -9,11 +9,17 @@ pub use privacy_boundary::TaprootMerkleBranch;
|
||||||
mod privacy_boundary {
|
mod privacy_boundary {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
internals::transparent_newtype! {
|
||||||
/// The Merkle proof for inclusion of a tree in a Taproot tree hash.
|
/// The Merkle proof for inclusion of a tree in a Taproot tree hash.
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct TaprootMerkleBranch([TapNodeHash]);
|
pub struct TaprootMerkleBranch([TapNodeHash]);
|
||||||
|
|
||||||
|
impl TaprootMerkleBranch {
|
||||||
|
pub(super) const fn from_hashes_unchecked(hashes: &_) -> &Self;
|
||||||
|
pub(super) fn from_mut_hashes_unchecked(hashes: &mut _) -> &mut Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TaprootMerkleBranch {
|
impl TaprootMerkleBranch {
|
||||||
/// Returns a reference to the slice of hashes.
|
/// Returns a reference to the slice of hashes.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -22,18 +28,6 @@ mod privacy_boundary {
|
||||||
/// Returns a reference to the mutable slice of hashes.
|
/// Returns a reference to the mutable slice of hashes.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_mut_slice(&mut self) -> &mut [TapNodeHash] { &mut self.0 }
|
pub fn as_mut_slice(&mut self) -> &mut [TapNodeHash] { &mut self.0 }
|
||||||
|
|
||||||
pub(super) const fn from_hashes_unchecked(hashes: &[TapNodeHash]) -> &Self {
|
|
||||||
unsafe {
|
|
||||||
&*(hashes as *const _ as *const Self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn from_mut_hashes_unchecked(hashes: &mut [TapNodeHash]) -> &mut Self {
|
|
||||||
unsafe {
|
|
||||||
&mut *(hashes as *mut _ as *mut Self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,11 +117,22 @@ pub(crate) use general_hash_type;
|
||||||
|
|
||||||
macro_rules! hash_type_no_default {
|
macro_rules! hash_type_no_default {
|
||||||
($bits:expr, $reverse:expr, $doc:literal) => {
|
($bits:expr, $reverse:expr, $doc:literal) => {
|
||||||
|
internals::transparent_newtype! {
|
||||||
#[doc = $doc]
|
#[doc = $doc]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct Hash([u8; $bits / 8]);
|
pub struct Hash([u8; $bits / 8]);
|
||||||
|
|
||||||
|
impl Hash {
|
||||||
|
/// Zero cost conversion between a fixed length byte array shared reference and
|
||||||
|
/// a shared reference to this Hash type.
|
||||||
|
pub fn from_bytes_ref(bytes: &_) -> &Self;
|
||||||
|
|
||||||
|
/// Zero cost conversion between a fixed length byte array exclusive reference and
|
||||||
|
/// an exclusive reference to this Hash type.
|
||||||
|
pub fn from_bytes_mut(bytes: &mut _) -> &mut Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Hash {
|
impl Hash {
|
||||||
const fn internal_new(arr: [u8; $bits / 8]) -> Self { Hash(arr) }
|
const fn internal_new(arr: [u8; $bits / 8]) -> Self { Hash(arr) }
|
||||||
|
|
||||||
|
@ -130,20 +141,6 @@ macro_rules! hash_type_no_default {
|
||||||
Self::internal_new(bytes)
|
Self::internal_new(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Zero cost conversion between a fixed length byte array shared reference and
|
|
||||||
/// a shared reference to this Hash type.
|
|
||||||
pub fn from_bytes_ref(bytes: &[u8; $bits / 8]) -> &Self {
|
|
||||||
// Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8]
|
|
||||||
unsafe { &*(bytes as *const _ as *const Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Zero cost conversion between a fixed length byte array exclusive reference and
|
|
||||||
/// an exclusive reference to this Hash type.
|
|
||||||
pub fn from_bytes_mut(bytes: &mut [u8; $bits / 8]) -> &mut Self {
|
|
||||||
// Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8]
|
|
||||||
unsafe { &mut *(bytes as *mut _ as *mut Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copies a byte slice into a hash object.
|
/// Copies a byte slice into a hash object.
|
||||||
#[deprecated(since = "0.15.0", note = "use `from_byte_array` instead")]
|
#[deprecated(since = "0.15.0", note = "use `from_byte_array` instead")]
|
||||||
#[allow(deprecated_in_future)] // Because of `FromSliceError`.
|
#[allow(deprecated_in_future)] // Because of `FromSliceError`.
|
||||||
|
|
|
@ -43,10 +43,21 @@ pub trait Tag {
|
||||||
const MIDSTATE: sha256::Midstate;
|
const MIDSTATE: sha256::Midstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internals::transparent_newtype! {
|
||||||
/// Output of the SHA256t hash function.
|
/// Output of the SHA256t hash function.
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct Hash<T>(PhantomData<T>, [u8; 32]);
|
pub struct Hash<T>(PhantomData<T>, [u8; 32]);
|
||||||
|
|
||||||
|
impl<T> Hash<T> {
|
||||||
|
/// Zero cost conversion between a fixed length byte array shared reference and
|
||||||
|
/// a shared reference to this Hash type.
|
||||||
|
pub fn from_bytes_ref(bytes: &_) -> &Self;
|
||||||
|
|
||||||
|
/// Zero cost conversion between a fixed length byte array exclusive reference and
|
||||||
|
/// an exclusive reference to this Hash type.
|
||||||
|
pub fn from_bytes_mut(bytes: &mut _) -> &mut Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Hash<T>
|
impl<T> Hash<T>
|
||||||
where
|
where
|
||||||
T: Tag,
|
T: Tag,
|
||||||
|
@ -56,20 +67,6 @@ where
|
||||||
/// Constructs a new hash from the underlying byte array.
|
/// Constructs a new hash from the underlying byte array.
|
||||||
pub const fn from_byte_array(bytes: [u8; 32]) -> Self { Self::internal_new(bytes) }
|
pub const fn from_byte_array(bytes: [u8; 32]) -> Self { Self::internal_new(bytes) }
|
||||||
|
|
||||||
/// Zero cost conversion between a fixed length byte array shared reference and
|
|
||||||
/// a shared reference to this Hash type.
|
|
||||||
pub fn from_bytes_ref(bytes: &[u8; 32]) -> &Self {
|
|
||||||
// Safety: Sound because Self is #[repr(transparent)] containing [u8; 32]
|
|
||||||
unsafe { &*(bytes as *const _ as *const Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Zero cost conversion between a fixed length byte array exclusive reference and
|
|
||||||
/// an exclusive reference to this Hash type.
|
|
||||||
pub fn from_bytes_mut(bytes: &mut [u8; 32]) -> &mut Self {
|
|
||||||
// Safety: Sound because Self is #[repr(transparent)] containing [u8; 32]
|
|
||||||
unsafe { &mut *(bytes as *mut _ as *mut Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copies a byte slice into a hash object.
|
/// Copies a byte slice into a hash object.
|
||||||
#[deprecated(since = "0.15.0", note = "use `from_byte_array` instead")]
|
#[deprecated(since = "0.15.0", note = "use `from_byte_array` instead")]
|
||||||
#[allow(deprecated_in_future)] // Because of `FromSliceError`.
|
#[allow(deprecated_in_future)] // Because of `FromSliceError`.
|
||||||
|
|
|
@ -35,6 +35,12 @@ pub mod rust_version {
|
||||||
include!(concat!(env!("OUT_DIR"), "/rust_version.rs"));
|
include!(concat!(env!("OUT_DIR"), "/rust_version.rs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod _export {
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
pub extern crate alloc;
|
||||||
|
}
|
||||||
|
|
||||||
pub mod array;
|
pub mod array;
|
||||||
pub mod array_vec;
|
pub mod array_vec;
|
||||||
pub mod compact_size;
|
pub mod compact_size;
|
||||||
|
|
|
@ -37,3 +37,211 @@ macro_rules! impl_to_hex_from_lower_hex {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a transparent wrapper around an inner type and soundly implements reference casts.
|
||||||
|
///
|
||||||
|
/// This macro takes care of several issues related to newtypes that need to allow casting their
|
||||||
|
/// inner types to themselves:
|
||||||
|
///
|
||||||
|
/// * It makes sure to put repr(transparent) on the type
|
||||||
|
/// * It optionally implements conversions from `&`, `&mut`, `Box`, `Rc`, `Arc`
|
||||||
|
/// * It makes sure to put `#[inline]` on all of these conversions since they are trivial
|
||||||
|
/// * It makes sure the reference cast is const
|
||||||
|
/// * It makes sure the `Arc` conversion is conditioned on `target_has_atomic = "ptr"`
|
||||||
|
///
|
||||||
|
/// Usage: just type the struct inside the macro as you would implementing it manually except leave
|
||||||
|
/// `#[repr(transparent)]` out. Then add an impl block for the just-defined type containing function
|
||||||
|
/// declarations that take a reference/smart pointer to `_` (use literal underscore; e.g. `&_` for
|
||||||
|
/// shared references) and return `Self` behind the appropriate "pointer" type. Do not write the
|
||||||
|
/// body, just semicolon.
|
||||||
|
///
|
||||||
|
/// The `alloc` types MUST NOT have import paths and don't need imports.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! transparent_newtype {
|
||||||
|
(
|
||||||
|
$(#[$($struct_attr:tt)*])*
|
||||||
|
$vis:vis struct $newtype:tt$(<$gen:ident $(= $default:ty)?>)?($($fields:tt)+) $(where $($where_ty:ty: $bound:path),* $(,)?)?;
|
||||||
|
|
||||||
|
impl$(<$gen2:tt>)? $newtype2:ident$(<$gen3:tt>)? {
|
||||||
|
$(
|
||||||
|
$(#[$($fn_attr:tt)*])*
|
||||||
|
$fn_vis:vis $(const)? fn $fn:ident($fn_arg_name:ident: $($fn_arg_ty:tt)+) -> $fn_ret_ty:ty;
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
$crate::_check_tts_eq!($newtype2, $newtype, "the type name in the impl block doesn't match the struct name");
|
||||||
|
$(
|
||||||
|
// WARNING: renaming has to be disabled for soundness!
|
||||||
|
// If it weren't it'd be possible to make the type inside struct not match the one passed
|
||||||
|
// to functions. In principle we could also omit the generics but that'd be confusing for
|
||||||
|
// readers.
|
||||||
|
$crate::_check_tts_eq!($gen2, $gen, "the name of the left generic parameter in impl block doesn't match the one on struct");
|
||||||
|
$crate::_check_tts_eq!($gen3, $gen, "the name of the right generic parameter in impl block doesn't match the one on struct");
|
||||||
|
)?
|
||||||
|
$(#[$($struct_attr)*])*
|
||||||
|
#[repr(transparent)]
|
||||||
|
$vis struct $newtype$(<$gen $(= $default)?>)?($($fields)+) $(where $($where_ty: $bound),*)?;
|
||||||
|
|
||||||
|
impl$(<$gen2>)? $newtype$(<$gen3>)? $(where $($where_ty: $bound),*)? {
|
||||||
|
$crate::_transparent_ref_conversions! {
|
||||||
|
$crate::_transparent_newtype_inner_type!($($fields)+);
|
||||||
|
$(
|
||||||
|
$(#[$($fn_attr)*])*
|
||||||
|
$fn_vis fn $fn($fn_arg_name: $($fn_arg_ty)+) -> $fn_ret_ty;
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! _transparent_ref_conversions {
|
||||||
|
(
|
||||||
|
$inner:ty;
|
||||||
|
$(
|
||||||
|
$(#[$($fn_attr:tt)*])*
|
||||||
|
$fn_vis:vis $(const)? fn $fn:ident($fn_arg_name:ident: $($fn_arg_ty:tt)+) -> $fn_ret_ty:ty;
|
||||||
|
)+
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
$crate::_transparent_ref_conversion! {
|
||||||
|
$inner;
|
||||||
|
$(#[$($fn_attr)*])*
|
||||||
|
$fn_vis fn $fn($fn_arg_name: $($fn_arg_ty)+) -> $fn_ret_ty;
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! _transparent_ref_conversion {
|
||||||
|
(
|
||||||
|
$inner:ty;
|
||||||
|
$(#[$($from_ref_attr:tt)*])*
|
||||||
|
$from_ref_vis:vis fn $from_ref:ident($from_ref_arg_name:ident: &_) -> $fn_ret_ty:ty;
|
||||||
|
) => {
|
||||||
|
#[inline]
|
||||||
|
$(#[$($from_ref_attr)*])*
|
||||||
|
$from_ref_vis const fn $from_ref($from_ref_arg_name: &$inner) -> &Self {
|
||||||
|
// SAFETY: the pointer is created by casting a pointer that is pointing to an object
|
||||||
|
// with the same layout and validity invariants and the previous pointer was created
|
||||||
|
// directly from a reference. (Notice repr(transparent).)
|
||||||
|
// The lifetime of the input reference matches the lifetime of the returned reference.
|
||||||
|
unsafe { &*($from_ref_arg_name as *const $inner as *const Self) }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
$inner:ty;
|
||||||
|
$(#[$($from_mut_attr:tt)*])*
|
||||||
|
$from_mut_vis:vis fn $from_mut:ident($from_mut_arg_name:ident: &mut _) -> $fn_ret_ty:ty;
|
||||||
|
) => {
|
||||||
|
#[inline]
|
||||||
|
$(#[$($from_mut_attr)*])*
|
||||||
|
$from_mut_vis fn $from_mut($from_mut_arg_name: &mut $inner) -> &mut Self {
|
||||||
|
// SAFETY: the pointer is created by casting a pointer that is pointing to an object
|
||||||
|
// with the same layout and validity invariants and the previous pointer was created
|
||||||
|
// directly from a reference. (Notice repr(transparent).)
|
||||||
|
// The lifetime of the input reference matches the lifetime of the returned reference.
|
||||||
|
unsafe { &mut *($from_mut_arg_name as *mut $inner as *mut Self) }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
$inner:ty;
|
||||||
|
$(#[$($from_box_attr:tt)*])*
|
||||||
|
$from_box_vis:vis fn $from_box:ident($from_box_arg_name:ident: Box<_>) -> $fn_ret_ty:ty;
|
||||||
|
) => {
|
||||||
|
$crate::_emit_alloc! {
|
||||||
|
$(#[$($from_box_attr)*])*
|
||||||
|
#[inline]
|
||||||
|
$from_box_vis fn $from_box($from_box_arg_name: $crate::_export::alloc::boxed::Box<$inner>) -> $crate::_export::alloc::boxed::Box<Self> {
|
||||||
|
let ptr = $crate::_export::alloc::boxed::Box::into_raw($from_box_arg_name);
|
||||||
|
// SAFETY: the pointer is created by casting a pointer that is pointing to an object
|
||||||
|
// with the same layout and validity invariants and the previous pointer was created
|
||||||
|
// directly from box. (Notice repr(transparent).)
|
||||||
|
unsafe { $crate::_export::alloc::boxed::Box::from_raw(ptr as *mut Self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
$inner:ty;
|
||||||
|
$(#[$($from_rc_attr:tt)*])*
|
||||||
|
$from_rc_vis:vis fn $from_rc:ident($from_rc_arg_name:ident: Rc<_>) -> $fn_ret_ty:ty;
|
||||||
|
) => {
|
||||||
|
$crate::_emit_alloc! {
|
||||||
|
$(#[$($from_rc_attr)*])*
|
||||||
|
#[inline]
|
||||||
|
$from_rc_vis fn $from_rc($from_rc_arg_name: $crate::_export::alloc::rc::Rc<$inner>) -> $crate::_export::alloc::rc::Rc<Self> {
|
||||||
|
let ptr = $crate::_export::alloc::rc::Rc::into_raw($from_rc_arg_name);
|
||||||
|
// SAFETY: the pointer is created by casting a pointer that is pointing to an object
|
||||||
|
// with the same layout and validity invariants and the previous pointer was created
|
||||||
|
// directly from box. (Notice repr(transparent).)
|
||||||
|
unsafe { $crate::_export::alloc::rc::Rc::from_raw(ptr as *mut Self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
$inner:ty;
|
||||||
|
$(#[$($from_arc_attr:tt)*])*
|
||||||
|
$from_arc_vis:vis fn $from_arc:ident($from_arc_arg_name:ident: Arc<_>) -> $fn_ret_ty:ty;
|
||||||
|
) => {
|
||||||
|
$crate::_emit_alloc! {
|
||||||
|
$(#[$($from_arc_attr)*])*
|
||||||
|
#[cfg(target_has_atomic = "ptr")]
|
||||||
|
#[inline]
|
||||||
|
$from_arc_vis fn $from_arc($from_arc_arg_name: $crate::_export::alloc::sync::Arc<$inner>) -> $crate::_export::alloc::sync::Arc<Self> {
|
||||||
|
let ptr = $crate::_export::alloc::sync::Arc::into_raw($from_arc_arg_name);
|
||||||
|
// SAFETY: the pointer is created by casting a pointer that is pointing to an object
|
||||||
|
// with the same layout and validity invariants and the previous pointer was created
|
||||||
|
// directly from box. (Notice repr(transparent).)
|
||||||
|
unsafe { $crate::_export::alloc::sync::Arc::from_raw(ptr as *mut Self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! _check_tts_eq {
|
||||||
|
($left:tt, $right:tt, $message:literal) => {
|
||||||
|
macro_rules! token_eq {
|
||||||
|
($right) => {};
|
||||||
|
($any:tt) => { compile_error!($message) };
|
||||||
|
}
|
||||||
|
token_eq!($left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! _transparent_newtype_inner_type {
|
||||||
|
($(#[$($field_attr:tt)*])* $inner:ty) => {
|
||||||
|
$inner
|
||||||
|
};
|
||||||
|
($(#[$($phantom_attr:tt)*])* PhantomData<$phantom:ty>, $(#[$($field_attr:tt)*])* $inner:ty) => {
|
||||||
|
$inner
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emits given tokens only if the `alloc` feature **in this crate** is enabled.
|
||||||
|
///
|
||||||
|
/// (The feature is currently enabled.)
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! _emit_alloc {
|
||||||
|
($($tokens:tt)*) => { $($tokens)* };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emits given tokens only if the `alloc` feature **in this crate** is enabled.
|
||||||
|
///
|
||||||
|
/// (The feature is currently disabled.)
|
||||||
|
#[cfg(not(feature = "alloc"))]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! _emit_alloc {
|
||||||
|
($($tokens:tt)*) => {};
|
||||||
|
}
|
||||||
|
|
|
@ -1,35 +1,26 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
|
|
||||||
use internals::rust_version;
|
use internals::rust_version;
|
||||||
|
|
||||||
|
internals::transparent_newtype! {
|
||||||
/// A bridging wrapper providing the I/O traits for types that already implement `std` I/O traits.
|
/// A bridging wrapper providing the I/O traits for types that already implement `std` I/O traits.
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FromStd<T>(T);
|
pub struct FromStd<T>(T);
|
||||||
|
|
||||||
|
impl<T> FromStd<T> {
|
||||||
|
/// Wraps a mutable reference to I/O type.
|
||||||
|
pub fn new_mut(inner: &mut _) -> &mut Self;
|
||||||
|
|
||||||
|
/// Wraps a boxed I/O type.
|
||||||
|
pub fn new_boxed(inner: Box<_>) -> Box<Self>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> FromStd<T> {
|
impl<T> FromStd<T> {
|
||||||
/// Wraps an I/O type.
|
/// Wraps an I/O type.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn new(inner: T) -> Self { Self(inner) }
|
pub const fn new(inner: T) -> Self { Self(inner) }
|
||||||
|
|
||||||
/// Wraps a mutable reference to I/O type.
|
|
||||||
#[inline]
|
|
||||||
pub fn new_mut(inner: &mut T) -> &mut Self {
|
|
||||||
// SAFETY: the type is repr(transparent) and the lifetimes match
|
|
||||||
unsafe { &mut *(inner as *mut _ as *mut Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wraps a boxed I/O type.
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
#[inline]
|
|
||||||
pub fn new_boxed(inner: Box<T>) -> Box<Self> {
|
|
||||||
// SAFETY: the type is repr(transparent) and the pointer is created from Box
|
|
||||||
unsafe { Box::from_raw(Box::into_raw(inner) as *mut Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the wrapped value.
|
/// Returns the wrapped value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_inner(self) -> T { self.0 }
|
pub fn into_inner(self) -> T { self.0 }
|
||||||
|
@ -117,31 +108,25 @@ impl<T: std::io::Write> std::io::Write for FromStd<T> {
|
||||||
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { self.0.write_all(buf) }
|
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { self.0.write_all(buf) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internals::transparent_newtype! {
|
||||||
/// A bridging wrapper providing the std traits for types that already implement our traits.
|
/// A bridging wrapper providing the std traits for types that already implement our traits.
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ToStd<T>(T);
|
pub struct ToStd<T>(T);
|
||||||
|
|
||||||
|
impl<T> ToStd<T> {
|
||||||
|
/// Wraps a mutable reference to I/O type.
|
||||||
|
pub fn new_mut(inner: &mut _) -> &mut Self;
|
||||||
|
|
||||||
|
/// Wraps a boxed I/O type.
|
||||||
|
pub fn new_boxed(inner: Box<_>) -> Box<Self>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> ToStd<T> {
|
impl<T> ToStd<T> {
|
||||||
/// Wraps an I/O type.
|
/// Wraps an I/O type.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn new(inner: T) -> Self { Self(inner) }
|
pub const fn new(inner: T) -> Self { Self(inner) }
|
||||||
|
|
||||||
/// Wraps a mutable reference to I/O type.
|
|
||||||
#[inline]
|
|
||||||
pub fn new_mut(inner: &mut T) -> &mut Self {
|
|
||||||
// SAFETY: the type is repr(transparent) and the lifetimes match
|
|
||||||
unsafe { &mut *(inner as *mut _ as *mut Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wraps a boxed I/O type.
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
#[inline]
|
|
||||||
pub fn new_boxed(inner: Box<T>) -> Box<Self> {
|
|
||||||
// SAFETY: the type is repr(transparent) and the pointer is created from Box
|
|
||||||
unsafe { Box::from_raw(Box::into_raw(inner) as *mut Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the wrapped value.
|
/// Returns the wrapped value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_inner(self) -> T { self.0 }
|
pub fn into_inner(self) -> T { self.0 }
|
||||||
|
|
|
@ -10,6 +10,7 @@ use arbitrary::{Arbitrary, Unstructured};
|
||||||
use super::ScriptBuf;
|
use super::ScriptBuf;
|
||||||
use crate::prelude::{Box, ToOwned, Vec};
|
use crate::prelude::{Box, ToOwned, Vec};
|
||||||
|
|
||||||
|
internals::transparent_newtype! {
|
||||||
/// Bitcoin script slice.
|
/// Bitcoin script slice.
|
||||||
///
|
///
|
||||||
/// *[See also the `bitcoin::script` module](super).*
|
/// *[See also the `bitcoin::script` module](super).*
|
||||||
|
@ -56,9 +57,21 @@ use crate::prelude::{Box, ToOwned, Vec};
|
||||||
/// * [CScript definition](https://github.com/bitcoin/bitcoin/blob/d492dc1cdaabdc52b0766bf4cba4bd73178325d0/src/script/script.h#L410)
|
/// * [CScript definition](https://github.com/bitcoin/bitcoin/blob/d492dc1cdaabdc52b0766bf4cba4bd73178325d0/src/script/script.h#L410)
|
||||||
///
|
///
|
||||||
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
|
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct Script([u8]);
|
pub struct Script([u8]);
|
||||||
|
|
||||||
|
impl Script {
|
||||||
|
/// Treat byte slice as `Script`
|
||||||
|
pub const fn from_bytes(bytes: &_) -> &Self;
|
||||||
|
|
||||||
|
/// Treat mutable byte slice as `Script`
|
||||||
|
pub fn from_bytes_mut(bytes: &mut _) -> &mut Self;
|
||||||
|
|
||||||
|
pub(crate) fn from_boxed_bytes(bytes: Box<_>) -> Box<Self>;
|
||||||
|
pub(crate) fn from_rc_bytes(bytes: Rc<_>) -> Rc<Self>;
|
||||||
|
pub(crate) fn from_arc_bytes(bytes: Arc<_>) -> Arc<Self>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for &Script {
|
impl Default for &Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Self { Script::new() }
|
fn default() -> Self { Script::new() }
|
||||||
|
@ -76,28 +89,6 @@ impl Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn new() -> &'static Self { Self::from_bytes(&[]) }
|
pub const fn new() -> &'static Self { Self::from_bytes(&[]) }
|
||||||
|
|
||||||
/// Treat byte slice as `Script`
|
|
||||||
#[inline]
|
|
||||||
pub const fn from_bytes(bytes: &[u8]) -> &Self {
|
|
||||||
// SAFETY: copied from `std`
|
|
||||||
// The pointer was just created from a reference which is still alive.
|
|
||||||
// Casting slice pointer to a transparent struct wrapping that slice is sound (same
|
|
||||||
// layout).
|
|
||||||
unsafe { &*(bytes as *const [u8] as *const Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Treat mutable byte slice as `Script`
|
|
||||||
#[inline]
|
|
||||||
pub fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self {
|
|
||||||
// SAFETY: copied from `std`
|
|
||||||
// The pointer was just created from a reference which is still alive.
|
|
||||||
// Casting slice pointer to a transparent struct wrapping that slice is sound (same
|
|
||||||
// layout).
|
|
||||||
// Function signature prevents callers from accessing `bytes` while the returned reference
|
|
||||||
// is alive.
|
|
||||||
unsafe { &mut *(bytes as *mut [u8] as *mut Self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the script data as a byte slice.
|
/// Returns the script data as a byte slice.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn as_bytes(&self) -> &[u8] { &self.0 }
|
pub const fn as_bytes(&self) -> &[u8] { &self.0 }
|
||||||
|
|
|
@ -277,24 +277,14 @@ impl<'a> From<&'a Script> for Cow<'a, Script> {
|
||||||
impl<'a> From<&'a Script> for Arc<Script> {
|
impl<'a> From<&'a Script> for Arc<Script> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: &'a Script) -> Self {
|
fn from(value: &'a Script) -> Self {
|
||||||
let rw: *const [u8] = Arc::into_raw(Arc::from(value.as_bytes()));
|
Script::from_arc_bytes(Arc::from(value.as_bytes()))
|
||||||
// SAFETY: copied from `std`
|
|
||||||
// The pointer was just created from an Arc without deallocating
|
|
||||||
// Casting a slice to a transparent struct wrapping that slice is sound (same
|
|
||||||
// layout).
|
|
||||||
unsafe { Arc::from_raw(rw as *const Script) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a Script> for Rc<Script> {
|
impl<'a> From<&'a Script> for Rc<Script> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: &'a Script) -> Self {
|
fn from(value: &'a Script) -> Self {
|
||||||
let rw: *const [u8] = Rc::into_raw(Rc::from(value.as_bytes()));
|
Script::from_rc_bytes(Rc::from(value.as_bytes()))
|
||||||
// SAFETY: copied from `std`
|
|
||||||
// The pointer was just created from an Rc without deallocating
|
|
||||||
// Casting a slice to a transparent struct wrapping that slice is sound (same
|
|
||||||
// layout).
|
|
||||||
unsafe { Rc::from_raw(rw as *const Script) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,9 +54,7 @@ impl ScriptBuf {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_boxed_script(self) -> Box<Script> {
|
pub fn into_boxed_script(self) -> Box<Script> {
|
||||||
// Copied from PathBuf::into_boxed_path
|
Script::from_boxed_bytes(self.into_bytes().into_boxed_slice())
|
||||||
let rw = Box::into_raw(self.into_bytes().into_boxed_slice()) as *mut Script;
|
|
||||||
unsafe { Box::from_raw(rw) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new empty script with pre-allocated capacity.
|
/// Constructs a new empty script with pre-allocated capacity.
|
||||||
|
|
Loading…
Reference in New Issue