Merge rust-bitcoin/rust-bitcoin#3156: impl IndexMut for PushBytes (already has Index) and fix/add docs

7c8601a696 implement IndexMut for PushBytes (Antoni Spaanderman)
71d760b3f2 Add and fix documentation on PushBytes's functions (Antoni Spaanderman)

Pull request description:

ACKs for top commit:
  Kixunil:
    ACK 7c8601a696
  tcharding:
    ACK 7c8601a696
  apoelstra:
    ACK 7c8601a696 successfully ran local tests

Tree-SHA512: a600dcda638cc727c2a31917e76c2e2f6da57b7044d571a345a919f1c471e0d30b82326492716eacfd9b3ce65c4484430bdd0f2d8ebbd220107cd9259a9faaa6
This commit is contained in:
merge-script 2024-08-12 13:30:01 +00:00
commit 5d8f4b2492
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
1 changed files with 37 additions and 14 deletions

View File

@ -15,7 +15,8 @@ pub use self::primitive::*;
/// break invariants. Therefore auditing this module should be sufficient. /// break invariants. Therefore auditing this module should be sufficient.
mod primitive { mod primitive {
use core::ops::{ use core::ops::{
Bound, Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Bound, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo,
RangeToInclusive,
}; };
use super::PushBytesError; use super::PushBytesError;
@ -43,53 +44,69 @@ mod primitive {
pub struct PushBytes([u8]); pub struct PushBytes([u8]);
impl PushBytes { impl PushBytes {
/// Creates `&Self` without checking the length. /// Creates `&PushBytes` without checking the length.
/// ///
/// # Safety /// # Safety
/// ///
/// The caller is responsible for checking that the length is less than the [`LIMIT`]. /// The caller is responsible for checking that the length is less than the 2^32.
unsafe fn from_slice_unchecked(bytes: &[u8]) -> &Self { unsafe fn from_slice_unchecked(bytes: &[u8]) -> &Self {
// SAFETY: The caller must guarantee that bytes.len() < 2^32.
// If that is the case the conversion is sound because &[u8] and &PushBytes
// have the same layout (because of #[repr(transparent)] on PushBytes).
&*(bytes as *const [u8] as *const PushBytes) &*(bytes as *const [u8] as *const PushBytes)
} }
/// Creates `&mut Self` without checking the length. /// Creates `&mut PushBytes` without checking the length.
/// ///
/// # Safety /// # Safety
/// ///
/// The caller is responsible for checking that the length is less than the [`LIMIT`]. /// The caller is responsible for checking that the length is less than the 2^32.
unsafe fn from_mut_slice_unchecked(bytes: &mut [u8]) -> &mut Self { unsafe fn from_mut_slice_unchecked(bytes: &mut [u8]) -> &mut Self {
// SAFETY: The caller must guarantee that bytes.len() < 2^32.
// If that is the case the conversion is sound because &mut [u8] and &mut PushBytes
// have the same layout (because of #[repr(transparent)] on PushBytes).
&mut *(bytes as *mut [u8] as *mut PushBytes) &mut *(bytes as *mut [u8] as *mut PushBytes)
} }
/// Creates an empty `PushBytes`. /// Creates an empty `&PushBytes`.
pub fn empty() -> &'static Self { pub fn empty() -> &'static Self {
// 0 < LIMIT // SAFETY: 0 < 2^32.
unsafe { Self::from_slice_unchecked(&[]) } unsafe { Self::from_slice_unchecked(&[]) }
} }
/// Returns the underlying bytes. /// Returns the underlying bytes.
pub fn as_bytes(&self) -> &[u8] { &self.0 } pub fn as_bytes(&self) -> &[u8] { &self.0 }
/// Returns the underlying mutbale bytes. /// Returns the underlying mutable bytes.
pub fn as_mut_bytes(&mut self) -> &mut [u8] { &mut self.0 } pub fn as_mut_bytes(&mut self) -> &mut [u8] { &mut self.0 }
} }
macro_rules! delegate_index { macro_rules! delegate_index {
($($type:ty),* $(,)?) => { ($($type:ty),* $(,)?) => {
$( $(
/// Script subslicing operation - read [slicing safety](#slicing-safety)!
impl Index<$type> for PushBytes { impl Index<$type> for PushBytes {
type Output = Self; type Output = Self;
#[inline] #[inline]
#[track_caller] #[track_caller]
fn index(&self, index: $type) -> &Self::Output { fn index(&self, index: $type) -> &Self::Output {
// Slicing can not make slices longer // SAFETY: Slicing can not make slices longer.
unsafe { unsafe {
Self::from_slice_unchecked(&self.0[index]) Self::from_slice_unchecked(&self.0[index])
} }
} }
} }
impl IndexMut<$type> for PushBytes {
#[inline]
#[track_caller]
fn index_mut(&mut self, index: $type) -> &mut Self::Output {
// SAFETY: Slicing can not make slices longer.
unsafe {
Self::from_mut_slice_unchecked(&mut self.0[index])
}
}
}
)* )*
} }
} }
@ -112,12 +129,18 @@ mod primitive {
fn index(&self, index: usize) -> &Self::Output { &self.0[index] } fn index(&self, index: usize) -> &Self::Output { &self.0[index] }
} }
impl IndexMut<usize> for PushBytes {
#[inline]
#[track_caller]
fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut self.0[index] }
}
impl<'a> TryFrom<&'a [u8]> for &'a PushBytes { impl<'a> TryFrom<&'a [u8]> for &'a PushBytes {
type Error = PushBytesError; type Error = PushBytesError;
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> { fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
check_limit(bytes.len())?; check_limit(bytes.len())?;
// We've just checked the length // SAFETY: We've just checked the length.
Ok(unsafe { PushBytes::from_slice_unchecked(bytes) }) Ok(unsafe { PushBytes::from_slice_unchecked(bytes) })
} }
} }
@ -127,7 +150,7 @@ mod primitive {
fn try_from(bytes: &'a mut [u8]) -> Result<Self, Self::Error> { fn try_from(bytes: &'a mut [u8]) -> Result<Self, Self::Error> {
check_limit(bytes.len())?; check_limit(bytes.len())?;
// We've just checked the length // SAFETY: We've just checked the length.
Ok(unsafe { PushBytes::from_mut_slice_unchecked(bytes) }) Ok(unsafe { PushBytes::from_mut_slice_unchecked(bytes) })
} }
} }
@ -139,7 +162,7 @@ mod primitive {
fn from(bytes: &'a [u8; $len]) -> Self { fn from(bytes: &'a [u8; $len]) -> Self {
// Check that the macro wasn't called with a wrong number. // Check that the macro wasn't called with a wrong number.
const _: () = [(); 1][($len >= 0x100000000u64) as usize]; const _: () = [(); 1][($len >= 0x100000000u64) as usize];
// We know the size of array statically and we checked macro input. // SAFETY: We know the size of array statically and we checked macro input.
unsafe { PushBytes::from_slice_unchecked(bytes) } unsafe { PushBytes::from_slice_unchecked(bytes) }
} }
} }
@ -147,7 +170,7 @@ mod primitive {
impl<'a> From<&'a mut [u8; $len]> for &'a mut PushBytes { impl<'a> From<&'a mut [u8; $len]> for &'a mut PushBytes {
fn from(bytes: &'a mut [u8; $len]) -> Self { fn from(bytes: &'a mut [u8; $len]) -> Self {
// Macro check already above, no need to duplicate. // Macro check already above, no need to duplicate.
// We know the size of array statically and we checked macro input. // SAFETY: We know the size of array statically and we checked macro input.
unsafe { PushBytes::from_mut_slice_unchecked(bytes) } unsafe { PushBytes::from_mut_slice_unchecked(bytes) }
} }
} }