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,96 +308,101 @@ pub enum AddressData {
|
|||
},
|
||||
}
|
||||
|
||||
/// A Bitcoin address.
|
||||
///
|
||||
/// ### Parsing addresses
|
||||
///
|
||||
/// When parsing string as an address, one has to pay attention to the network, on which the parsed
|
||||
/// address is supposed to be valid. For the purpose of this validation, `Address` has
|
||||
/// [`is_valid_for_network`](Address<NetworkUnchecked>::is_valid_for_network) method. In order to provide more safety,
|
||||
/// enforced by compiler, `Address` also contains a special marker type, which indicates whether network of the parsed
|
||||
/// address has been checked. This marker type will prevent from calling certain functions unless the network
|
||||
/// verification has been successfully completed.
|
||||
///
|
||||
/// The result of parsing an address is `Address<NetworkUnchecked>` suggesting that network of the parsed address
|
||||
/// has not yet been verified. To perform this verification, method [`require_network`](Address<NetworkUnchecked>::require_network)
|
||||
/// can be called, providing network on which the address is supposed to be valid. If the verification succeeds,
|
||||
/// `Address<NetworkChecked>` is returned.
|
||||
///
|
||||
/// The types `Address` and `Address<NetworkChecked>` are synonymous, i. e. they can be used interchangeably.
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::str::FromStr;
|
||||
/// use bitcoin::{Address, Network};
|
||||
/// use bitcoin::address::{NetworkUnchecked, NetworkChecked};
|
||||
///
|
||||
/// // variant 1
|
||||
/// let address: Address<NetworkUnchecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap();
|
||||
/// let _address: Address<NetworkChecked> = address.require_network(Network::Bitcoin).unwrap();
|
||||
///
|
||||
/// // variant 2
|
||||
/// let _address: Address = Address::from_str("32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf").unwrap()
|
||||
/// .require_network(Network::Bitcoin).unwrap();
|
||||
///
|
||||
/// // variant 3
|
||||
/// let _address: Address<NetworkChecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse::<Address<_>>()
|
||||
/// .unwrap().require_network(Network::Bitcoin).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// ### Formatting addresses
|
||||
///
|
||||
/// To format address into its textual representation, both `Debug` (for usage in programmer-facing,
|
||||
/// debugging context) and `Display` (for user-facing output) can be used, with the following caveats:
|
||||
///
|
||||
/// 1. `Display` is implemented only for `Address<NetworkChecked>`:
|
||||
///
|
||||
/// ```
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkChecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap().assume_checked();
|
||||
/// assert_eq!(address.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
|
||||
/// ```
|
||||
///
|
||||
/// ```ignore
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkUnchecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap();
|
||||
/// let s = address.to_string(); // does not compile
|
||||
/// ```
|
||||
///
|
||||
/// 2. `Debug` on `Address<NetworkUnchecked>` does not produce clean address but address wrapped by
|
||||
/// an indicator that its network has not been checked. This is to encourage programmer to properly
|
||||
/// check the network and use `Display` in user-facing context.
|
||||
///
|
||||
/// ```
|
||||
/// # use bitcoin::address::{Address, NetworkUnchecked};
|
||||
/// let address: Address<NetworkUnchecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap();
|
||||
/// assert_eq!(format!("{:?}", address), "Address<NetworkUnchecked>(132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM)");
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkChecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap().assume_checked();
|
||||
/// assert_eq!(format!("{:?}", address), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
|
||||
/// ```
|
||||
///
|
||||
/// ### Relevant BIPs
|
||||
///
|
||||
/// * [BIP13 - Address Format for pay-to-script-hash](https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki)
|
||||
/// * [BIP16 - Pay to Script Hash](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki)
|
||||
/// * [BIP141 - Segregated Witness (Consensus layer)](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki)
|
||||
/// * [BIP142 - Address Format for Segregated Witness](https://github.com/bitcoin/bips/blob/master/bip-0142.mediawiki)
|
||||
/// * [BIP341 - Taproot: SegWit version 1 spending rules](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki)
|
||||
/// * [BIP350 - Bech32m format for v1+ witness addresses](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki)
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
// 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.
|
||||
#[repr(transparent)]
|
||||
pub struct Address<V = NetworkChecked>(PhantomData<V>, AddressInner)
|
||||
where
|
||||
V: NetworkValidation;
|
||||
internals::transparent_newtype! {
|
||||
/// A Bitcoin address.
|
||||
///
|
||||
/// ### Parsing addresses
|
||||
///
|
||||
/// When parsing string as an address, one has to pay attention to the network, on which the parsed
|
||||
/// address is supposed to be valid. For the purpose of this validation, `Address` has
|
||||
/// [`is_valid_for_network`](Address<NetworkUnchecked>::is_valid_for_network) method. In order to provide more safety,
|
||||
/// enforced by compiler, `Address` also contains a special marker type, which indicates whether network of the parsed
|
||||
/// address has been checked. This marker type will prevent from calling certain functions unless the network
|
||||
/// verification has been successfully completed.
|
||||
///
|
||||
/// The result of parsing an address is `Address<NetworkUnchecked>` suggesting that network of the parsed address
|
||||
/// has not yet been verified. To perform this verification, method [`require_network`](Address<NetworkUnchecked>::require_network)
|
||||
/// can be called, providing network on which the address is supposed to be valid. If the verification succeeds,
|
||||
/// `Address<NetworkChecked>` is returned.
|
||||
///
|
||||
/// The types `Address` and `Address<NetworkChecked>` are synonymous, i. e. they can be used interchangeably.
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::str::FromStr;
|
||||
/// use bitcoin::{Address, Network};
|
||||
/// use bitcoin::address::{NetworkUnchecked, NetworkChecked};
|
||||
///
|
||||
/// // variant 1
|
||||
/// let address: Address<NetworkUnchecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap();
|
||||
/// let _address: Address<NetworkChecked> = address.require_network(Network::Bitcoin).unwrap();
|
||||
///
|
||||
/// // variant 2
|
||||
/// let _address: Address = Address::from_str("32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf").unwrap()
|
||||
/// .require_network(Network::Bitcoin).unwrap();
|
||||
///
|
||||
/// // variant 3
|
||||
/// let _address: Address<NetworkChecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse::<Address<_>>()
|
||||
/// .unwrap().require_network(Network::Bitcoin).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// ### Formatting addresses
|
||||
///
|
||||
/// To format address into its textual representation, both `Debug` (for usage in programmer-facing,
|
||||
/// debugging context) and `Display` (for user-facing output) can be used, with the following caveats:
|
||||
///
|
||||
/// 1. `Display` is implemented only for `Address<NetworkChecked>`:
|
||||
///
|
||||
/// ```
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkChecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap().assume_checked();
|
||||
/// assert_eq!(address.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
|
||||
/// ```
|
||||
///
|
||||
/// ```ignore
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkUnchecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap();
|
||||
/// let s = address.to_string(); // does not compile
|
||||
/// ```
|
||||
///
|
||||
/// 2. `Debug` on `Address<NetworkUnchecked>` does not produce clean address but address wrapped by
|
||||
/// an indicator that its network has not been checked. This is to encourage programmer to properly
|
||||
/// check the network and use `Display` in user-facing context.
|
||||
///
|
||||
/// ```
|
||||
/// # use bitcoin::address::{Address, NetworkUnchecked};
|
||||
/// let address: Address<NetworkUnchecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap();
|
||||
/// assert_eq!(format!("{:?}", address), "Address<NetworkUnchecked>(132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM)");
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkChecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap().assume_checked();
|
||||
/// assert_eq!(format!("{:?}", address), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
|
||||
/// ```
|
||||
///
|
||||
/// ### Relevant BIPs
|
||||
///
|
||||
/// * [BIP13 - Address Format for pay-to-script-hash](https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki)
|
||||
/// * [BIP16 - Pay to Script Hash](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki)
|
||||
/// * [BIP141 - Segregated Witness (Consensus layer)](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki)
|
||||
/// * [BIP142 - Address Format for Segregated Witness](https://github.com/bitcoin/bips/blob/master/bip-0142.mediawiki)
|
||||
/// * [BIP341 - Taproot: SegWit version 1 spending rules](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki)
|
||||
/// * [BIP350 - Bech32m format for v1+ witness addresses](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki)
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
// 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.
|
||||
pub struct Address<V = NetworkChecked>(PhantomData<V>, AddressInner)
|
||||
where
|
||||
V: NetworkValidation;
|
||||
|
||||
impl<V> Address<V> {
|
||||
fn from_inner_ref(inner: &_) -> &Self;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
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.
|
||||
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.
|
||||
|
@ -803,7 +808,7 @@ impl Address<NetworkUnchecked> {
|
|||
///
|
||||
/// This function is dangerous in case the address is not a valid checked 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,
|
||||
|
|
|
@ -35,33 +35,29 @@ mod primitive {
|
|||
}
|
||||
}
|
||||
|
||||
/// Byte slices that can be in Bitcoin script.
|
||||
///
|
||||
/// 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
|
||||
/// the script safely.
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct PushBytes([u8]);
|
||||
internals::transparent_newtype! {
|
||||
/// Byte slices that can be in Bitcoin script.
|
||||
///
|
||||
/// 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
|
||||
/// the script safely.
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct PushBytes([u8]);
|
||||
|
||||
impl PushBytes {
|
||||
/// Constructs a new `&PushBytes` without checking the length.
|
||||
///
|
||||
/// The caller is responsible for checking that the length is less than the 2^32.
|
||||
fn from_slice_unchecked(bytes: &_) -> &Self;
|
||||
|
||||
/// Constructs a new `&mut PushBytes` without checking the length.
|
||||
///
|
||||
/// The caller is responsible for checking that the length is less than the 2^32.
|
||||
fn from_mut_slice_unchecked(bytes: &mut _) -> &mut Self;
|
||||
}
|
||||
}
|
||||
|
||||
impl PushBytes {
|
||||
/// Constructs a new `&PushBytes` without checking the length.
|
||||
///
|
||||
/// The caller is responsible for checking that the length is less than the 2^32.
|
||||
fn from_slice_unchecked(bytes: &[u8]) -> &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.
|
||||
///
|
||||
/// 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 {
|
||||
// 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) }
|
||||
}
|
||||
|
||||
/// Constructs an empty `&PushBytes`.
|
||||
pub fn empty() -> &'static Self { Self::from_slice_unchecked(&[]) }
|
||||
|
|
|
@ -9,10 +9,16 @@ pub use privacy_boundary::TaprootMerkleBranch;
|
|||
mod privacy_boundary {
|
||||
use super::*;
|
||||
|
||||
/// The Merkle proof for inclusion of a tree in a Taproot tree hash.
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct TaprootMerkleBranch([TapNodeHash]);
|
||||
internals::transparent_newtype! {
|
||||
/// The Merkle proof for inclusion of a tree in a Taproot tree hash.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
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 {
|
||||
/// Returns a reference to the slice of hashes.
|
||||
|
@ -22,18 +28,6 @@ mod privacy_boundary {
|
|||
/// Returns a reference to the mutable slice of hashes.
|
||||
#[inline]
|
||||
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,10 +117,21 @@ pub(crate) use general_hash_type;
|
|||
|
||||
macro_rules! hash_type_no_default {
|
||||
($bits:expr, $reverse:expr, $doc:literal) => {
|
||||
#[doc = $doc]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct Hash([u8; $bits / 8]);
|
||||
internals::transparent_newtype! {
|
||||
#[doc = $doc]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[deprecated(since = "0.15.0", note = "use `from_byte_array` instead")]
|
||||
#[allow(deprecated_in_future)] // Because of `FromSliceError`.
|
||||
|
|
|
@ -43,9 +43,20 @@ pub trait Tag {
|
|||
const MIDSTATE: sha256::Midstate;
|
||||
}
|
||||
|
||||
/// Output of the SHA256t hash function.
|
||||
#[repr(transparent)]
|
||||
pub struct Hash<T>(PhantomData<T>, [u8; 32]);
|
||||
internals::transparent_newtype! {
|
||||
/// Output of the SHA256t hash function.
|
||||
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>
|
||||
where
|
||||
|
@ -56,20 +67,6 @@ where
|
|||
/// Constructs a new hash from the underlying byte array.
|
||||
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.
|
||||
#[deprecated(since = "0.15.0", note = "use `from_byte_array` instead")]
|
||||
#[allow(deprecated_in_future)] // Because of `FromSliceError`.
|
||||
|
|
|
@ -35,6 +35,12 @@ pub mod rust_version {
|
|||
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_vec;
|
||||
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
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use internals::rust_version;
|
||||
|
||||
/// A bridging wrapper providing the I/O traits for types that already implement `std` I/O traits.
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct FromStd<T>(T);
|
||||
internals::transparent_newtype! {
|
||||
/// A bridging wrapper providing the I/O traits for types that already implement `std` I/O traits.
|
||||
#[derive(Debug)]
|
||||
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> {
|
||||
/// Wraps an I/O type.
|
||||
#[inline]
|
||||
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.
|
||||
#[inline]
|
||||
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) }
|
||||
}
|
||||
|
||||
/// A bridging wrapper providing the std traits for types that already implement our traits.
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct ToStd<T>(T);
|
||||
internals::transparent_newtype! {
|
||||
/// A bridging wrapper providing the std traits for types that already implement our traits.
|
||||
#[derive(Debug)]
|
||||
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> {
|
||||
/// Wraps an I/O type.
|
||||
#[inline]
|
||||
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.
|
||||
#[inline]
|
||||
pub fn into_inner(self) -> T { self.0 }
|
||||
|
|
|
@ -10,54 +10,67 @@ use arbitrary::{Arbitrary, Unstructured};
|
|||
use super::ScriptBuf;
|
||||
use crate::prelude::{Box, ToOwned, Vec};
|
||||
|
||||
/// Bitcoin script slice.
|
||||
///
|
||||
/// *[See also the `bitcoin::script` module](super).*
|
||||
///
|
||||
/// `Script` is a script slice, the most primitive script type. It's usually seen in its borrowed
|
||||
/// form `&Script`. It is always encoded as a series of bytes representing the opcodes and data
|
||||
/// pushes.
|
||||
///
|
||||
/// ## Validity
|
||||
///
|
||||
/// `Script` does not have any validity invariants - it's essentially just a marked slice of
|
||||
/// bytes. This is similar to [`Path`](std::path::Path) vs [`OsStr`](std::ffi::OsStr) where they
|
||||
/// are trivially cast-able to each-other and `Path` doesn't guarantee being a usable FS path but
|
||||
/// having a newtype still has value because of added methods, readability and basic type checking.
|
||||
///
|
||||
/// Although at least data pushes could be checked not to overflow the script, bad scripts are
|
||||
/// allowed to be in a transaction (outputs just become unspendable) and there even are such
|
||||
/// transactions in the chain. Thus we must allow such scripts to be placed in the transaction.
|
||||
///
|
||||
/// ## Slicing safety
|
||||
///
|
||||
/// Slicing is similar to how `str` works: some ranges may be incorrect and indexing by
|
||||
/// `usize` is not supported. However, as opposed to `std`, we have no way of checking
|
||||
/// correctness without causing linear complexity so there are **no panics on invalid
|
||||
/// ranges!** If you supply an invalid range, you'll get a garbled script.
|
||||
///
|
||||
/// The range is considered valid if it's at a boundary of instruction. Care must be taken
|
||||
/// especially with push operations because you could get a reference to arbitrary
|
||||
/// attacker-supplied bytes that look like a valid script.
|
||||
///
|
||||
/// It is recommended to use `.instructions()` method to get an iterator over script
|
||||
/// instructions and work with that instead.
|
||||
///
|
||||
/// ## Memory safety
|
||||
///
|
||||
/// The type is `#[repr(transparent)]` for internal purposes only!
|
||||
/// No consumer crate may rely on the representation of the struct!
|
||||
///
|
||||
/// ## References
|
||||
///
|
||||
///
|
||||
/// ### Bitcoin Core References
|
||||
///
|
||||
/// * [CScript definition](https://github.com/bitcoin/bitcoin/blob/d492dc1cdaabdc52b0766bf4cba4bd73178325d0/src/script/script.h#L410)
|
||||
///
|
||||
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct Script([u8]);
|
||||
internals::transparent_newtype! {
|
||||
/// Bitcoin script slice.
|
||||
///
|
||||
/// *[See also the `bitcoin::script` module](super).*
|
||||
///
|
||||
/// `Script` is a script slice, the most primitive script type. It's usually seen in its borrowed
|
||||
/// form `&Script`. It is always encoded as a series of bytes representing the opcodes and data
|
||||
/// pushes.
|
||||
///
|
||||
/// ## Validity
|
||||
///
|
||||
/// `Script` does not have any validity invariants - it's essentially just a marked slice of
|
||||
/// bytes. This is similar to [`Path`](std::path::Path) vs [`OsStr`](std::ffi::OsStr) where they
|
||||
/// are trivially cast-able to each-other and `Path` doesn't guarantee being a usable FS path but
|
||||
/// having a newtype still has value because of added methods, readability and basic type checking.
|
||||
///
|
||||
/// Although at least data pushes could be checked not to overflow the script, bad scripts are
|
||||
/// allowed to be in a transaction (outputs just become unspendable) and there even are such
|
||||
/// transactions in the chain. Thus we must allow such scripts to be placed in the transaction.
|
||||
///
|
||||
/// ## Slicing safety
|
||||
///
|
||||
/// Slicing is similar to how `str` works: some ranges may be incorrect and indexing by
|
||||
/// `usize` is not supported. However, as opposed to `std`, we have no way of checking
|
||||
/// correctness without causing linear complexity so there are **no panics on invalid
|
||||
/// ranges!** If you supply an invalid range, you'll get a garbled script.
|
||||
///
|
||||
/// The range is considered valid if it's at a boundary of instruction. Care must be taken
|
||||
/// especially with push operations because you could get a reference to arbitrary
|
||||
/// attacker-supplied bytes that look like a valid script.
|
||||
///
|
||||
/// It is recommended to use `.instructions()` method to get an iterator over script
|
||||
/// instructions and work with that instead.
|
||||
///
|
||||
/// ## Memory safety
|
||||
///
|
||||
/// The type is `#[repr(transparent)]` for internal purposes only!
|
||||
/// No consumer crate may rely on the representation of the struct!
|
||||
///
|
||||
/// ## References
|
||||
///
|
||||
///
|
||||
/// ### Bitcoin Core References
|
||||
///
|
||||
/// * [CScript definition](https://github.com/bitcoin/bitcoin/blob/d492dc1cdaabdc52b0766bf4cba4bd73178325d0/src/script/script.h#L410)
|
||||
///
|
||||
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||
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 {
|
||||
#[inline]
|
||||
|
@ -76,28 +89,6 @@ impl Script {
|
|||
#[inline]
|
||||
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.
|
||||
#[inline]
|
||||
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> {
|
||||
#[inline]
|
||||
fn from(value: &'a Script) -> Self {
|
||||
let rw: *const [u8] = Arc::into_raw(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) }
|
||||
Script::from_arc_bytes(Arc::from(value.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Script> for Rc<Script> {
|
||||
#[inline]
|
||||
fn from(value: &'a Script) -> Self {
|
||||
let rw: *const [u8] = Rc::into_raw(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) }
|
||||
Script::from_rc_bytes(Rc::from(value.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,9 +54,7 @@ impl ScriptBuf {
|
|||
#[must_use]
|
||||
#[inline]
|
||||
pub fn into_boxed_script(self) -> Box<Script> {
|
||||
// Copied from PathBuf::into_boxed_path
|
||||
let rw = Box::into_raw(self.into_bytes().into_boxed_slice()) as *mut Script;
|
||||
unsafe { Box::from_raw(rw) }
|
||||
Script::from_boxed_bytes(self.into_bytes().into_boxed_slice())
|
||||
}
|
||||
|
||||
/// Constructs a new empty script with pre-allocated capacity.
|
||||
|
|
Loading…
Reference in New Issue