Make `Script` and `ScriptBuf` obey sanity rules

The newtype sanity rules (a name I came up with):
* Newtypes should have at most one constructor that directly references
  the inner field.
* Newtypes should have at most three accessor methods that directly
  reference the ineer field: one for owned access, the second for
  borrowed and the third for mutably borrowed.
* All other methods should use the methods above to perform operations
  on the newtype and not directly access the fields.

This commit makes `Script` and `ScriptBuf` obey these except for
`reserve` and `reserve_exact` since we don't have `as_mut_vec` method.
As a side effect it also adds `const` to `ScriptBuf::from_bytes`.
This commit is contained in:
Martin Habovstiak 2025-02-20 15:35:17 +01:00
parent e487618503
commit 277223da6a
3 changed files with 21 additions and 21 deletions

View File

@ -54,7 +54,7 @@ use crate::prelude::{Box, ToOwned, Vec};
/// ///
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] #[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
#[repr(transparent)] #[repr(transparent)]
pub struct Script(pub(in crate::script) [u8]); pub struct Script([u8]);
impl Default for &Script { impl Default for &Script {
#[inline] #[inline]
@ -64,7 +64,7 @@ impl Default for &Script {
impl ToOwned for Script { impl ToOwned for Script {
type Owned = ScriptBuf; type Owned = ScriptBuf;
fn to_owned(&self) -> Self::Owned { ScriptBuf(self.0.to_owned()) } fn to_owned(&self) -> Self::Owned { ScriptBuf::from_bytes(self.to_vec()) }
} }
impl Script { impl Script {
@ -104,7 +104,7 @@ impl Script {
/// Returns a copy of the script data. /// Returns a copy of the script data.
#[inline] #[inline]
pub fn to_vec(&self) -> Vec<u8> { self.0.to_owned() } pub fn to_vec(&self) -> Vec<u8> { self.as_bytes().to_owned() }
/// Returns a copy of the script data. /// Returns a copy of the script data.
#[inline] #[inline]
@ -113,11 +113,11 @@ impl Script {
/// Returns the length in bytes of the script. /// Returns the length in bytes of the script.
#[inline] #[inline]
pub fn len(&self) -> usize { self.0.len() } pub fn len(&self) -> usize { self.as_bytes().len() }
/// Returns whether the script is the empty script. /// Returns whether the script is the empty script.
#[inline] #[inline]
pub fn is_empty(&self) -> bool { self.0.is_empty() } pub fn is_empty(&self) -> bool { self.as_bytes().is_empty() }
/// Converts a [`Box<Script>`](Box) into a [`ScriptBuf`] without copying or allocating. /// Converts a [`Box<Script>`](Box) into a [`ScriptBuf`] without copying or allocating.
#[must_use] #[must_use]
@ -128,7 +128,7 @@ impl Script {
// Casting a transparent struct wrapping a slice to the slice pointer is sound (same // Casting a transparent struct wrapping a slice to the slice pointer is sound (same
// layout). // layout).
let inner = unsafe { Box::from_raw(rw) }; let inner = unsafe { Box::from_raw(rw) };
ScriptBuf(Vec::from(inner)) ScriptBuf::from_bytes(Vec::from(inner))
} }
} }
@ -141,7 +141,7 @@ macro_rules! delegate_index {
#[inline] #[inline]
fn index(&self, index: $type) -> &Self::Output { fn index(&self, index: $type) -> &Self::Output {
Self::from_bytes(&self.0[index]) Self::from_bytes(&self.as_bytes()[index])
} }
} }
)* )*

View File

@ -236,7 +236,7 @@ impl<'a> From<&'a Script> for Cow<'a, Script> {
#[cfg(target_has_atomic = "ptr")] #[cfg(target_has_atomic = "ptr")]
impl<'a> From<&'a Script> for Arc<Script> { impl<'a> From<&'a Script> for Arc<Script> {
fn from(value: &'a Script) -> Self { fn from(value: &'a Script) -> Self {
let rw: *const [u8] = Arc::into_raw(Arc::from(&value.0)); let rw: *const [u8] = Arc::into_raw(Arc::from(value.as_bytes()));
// SAFETY: copied from `std` // SAFETY: copied from `std`
// The pointer was just created from an Arc without deallocating // The pointer was just created from an Arc without deallocating
// Casting a slice to a transparent struct wrapping that slice is sound (same // Casting a slice to a transparent struct wrapping that slice is sound (same
@ -247,7 +247,7 @@ impl<'a> From<&'a Script> for Arc<Script> {
impl<'a> From<&'a Script> for Rc<Script> { impl<'a> From<&'a Script> for Rc<Script> {
fn from(value: &'a Script) -> Self { fn from(value: &'a Script) -> Self {
let rw: *const [u8] = Rc::into_raw(Rc::from(&value.0)); let rw: *const [u8] = Rc::into_raw(Rc::from(value.as_bytes()));
// SAFETY: copied from `std` // SAFETY: copied from `std`
// The pointer was just created from an Rc without deallocating // The pointer was just created from an Rc without deallocating
// Casting a slice to a transparent struct wrapping that slice is sound (same // Casting a slice to a transparent struct wrapping that slice is sound (same
@ -257,11 +257,11 @@ impl<'a> From<&'a Script> for Rc<Script> {
} }
impl From<Vec<u8>> for ScriptBuf { impl From<Vec<u8>> for ScriptBuf {
fn from(v: Vec<u8>) -> Self { ScriptBuf(v) } fn from(v: Vec<u8>) -> Self { ScriptBuf::from_bytes(v) }
} }
impl From<ScriptBuf> for Vec<u8> { impl From<ScriptBuf> for Vec<u8> {
fn from(v: ScriptBuf) -> Self { v.0 } fn from(v: ScriptBuf) -> Self { v.into_bytes() }
} }
impl AsRef<Script> for Script { impl AsRef<Script> for Script {
@ -418,11 +418,11 @@ impl fmt::UpperHex for ScriptBuf {
impl Deref for ScriptBuf { impl Deref for ScriptBuf {
type Target = Script; type Target = Script;
fn deref(&self) -> &Self::Target { Script::from_bytes(&self.0) } fn deref(&self) -> &Self::Target { self.as_script() }
} }
impl DerefMut for ScriptBuf { impl DerefMut for ScriptBuf {
fn deref_mut(&mut self) -> &mut Self::Target { Script::from_bytes_mut(&mut self.0) } fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_script() }
} }
impl Borrow<Script> for ScriptBuf { impl Borrow<Script> for ScriptBuf {

View File

@ -19,17 +19,17 @@ use crate::prelude::{Box, Vec};
/// ///
/// [deref coercions]: https://doc.rust-lang.org/std/ops/trait.Deref.html#more-on-deref-coercion /// [deref coercions]: https://doc.rust-lang.org/std/ops/trait.Deref.html#more-on-deref-coercion
#[derive(Default, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] #[derive(Default, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct ScriptBuf(pub(in crate::script) Vec<u8>); pub struct ScriptBuf(Vec<u8>);
impl ScriptBuf { impl ScriptBuf {
/// Constructs a new empty script. /// Constructs a new empty script.
#[inline] #[inline]
pub const fn new() -> Self { ScriptBuf(Vec::new()) } pub const fn new() -> Self { ScriptBuf::from_bytes(Vec::new()) }
/// Converts byte vector into script. /// Converts byte vector into script.
/// ///
/// This method doesn't (re)allocate. /// This method doesn't (re)allocate.
pub fn from_bytes(bytes: Vec<u8>) -> Self { ScriptBuf(bytes) } pub const fn from_bytes(bytes: Vec<u8>) -> Self { ScriptBuf(bytes) }
/// Returns a reference to unsized script. /// Returns a reference to unsized script.
pub fn as_script(&self) -> &Script { Script::from_bytes(&self.0) } pub fn as_script(&self) -> &Script { Script::from_bytes(&self.0) }
@ -52,12 +52,12 @@ impl ScriptBuf {
#[inline] #[inline]
pub fn into_boxed_script(self) -> Box<Script> { pub fn into_boxed_script(self) -> Box<Script> {
// Copied from PathBuf::into_boxed_path // Copied from PathBuf::into_boxed_path
let rw = Box::into_raw(self.0.into_boxed_slice()) as *mut Script; let rw = Box::into_raw(self.into_bytes().into_boxed_slice()) as *mut Script;
unsafe { Box::from_raw(rw) } unsafe { Box::from_raw(rw) }
} }
/// Constructs a new empty script with pre-allocated capacity. /// Constructs a new empty script with pre-allocated capacity.
pub fn with_capacity(capacity: usize) -> Self { ScriptBuf(Vec::with_capacity(capacity)) } pub fn with_capacity(capacity: usize) -> Self { ScriptBuf::from_bytes(Vec::with_capacity(capacity)) }
/// Pre-allocates at least `additional_len` bytes if needed. /// Pre-allocates at least `additional_len` bytes if needed.
/// ///
@ -91,7 +91,7 @@ impl ScriptBuf {
impl<'a> Arbitrary<'a> for ScriptBuf { impl<'a> Arbitrary<'a> for ScriptBuf {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let v = Vec::<u8>::arbitrary(u)?; let v = Vec::<u8>::arbitrary(u)?;
Ok(ScriptBuf(v)) Ok(ScriptBuf::from_bytes(v))
} }
} }
@ -103,7 +103,7 @@ mod tests {
fn script_buf_from_bytes() { fn script_buf_from_bytes() {
let bytes = vec![1, 2, 3]; let bytes = vec![1, 2, 3];
let script = ScriptBuf::from_bytes(bytes.clone()); let script = ScriptBuf::from_bytes(bytes.clone());
assert_eq!(script.0, bytes); assert_eq!(script.as_bytes(), bytes);
} }
#[test] #[test]
@ -120,7 +120,7 @@ mod tests {
let mut script = ScriptBuf::from_bytes(bytes.clone()); let mut script = ScriptBuf::from_bytes(bytes.clone());
let script_mut_ref = script.as_mut_script(); let script_mut_ref = script.as_mut_script();
script_mut_ref.as_mut_bytes()[0] = 4; script_mut_ref.as_mut_bytes()[0] = 4;
assert_eq!(script.0, vec![4, 2, 3]); assert_eq!(script.as_mut_bytes(), vec![4, 2, 3]);
} }
#[test] #[test]