Put `#[inline]` on most `Script{Buf}` methods

These methods are either newtype casts that should compile to no-ops or
directly calling into some other function with at most some pointer
adjustments. As such making them `#[inline]` is definitely benefitial.
There are also methods that check length and then call some other
function. These are also worth inlining since the length could be known
at compile time and the check could be eliminated.
This commit is contained in:
Martin Habovstiak 2025-02-20 16:18:21 +01:00
parent b7e2af1b6b
commit 0567e6fe1d
3 changed files with 52 additions and 0 deletions

View File

@ -67,6 +67,7 @@ impl Default for &Script {
impl ToOwned for Script {
type Owned = ScriptBuf;
#[inline]
fn to_owned(&self) -> Self::Owned { ScriptBuf::from_bytes(self.to_vec()) }
}
@ -124,6 +125,7 @@ impl Script {
/// Converts a [`Box<Script>`](Box) into a [`ScriptBuf`] without copying or allocating.
#[must_use]
#[inline]
pub fn into_script_buf(self: Box<Self>) -> ScriptBuf {
let rw = Box::into_raw(self) as *mut [u8];
// SAFETY: copied from `std`
@ -137,6 +139,7 @@ impl Script {
#[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for &'a Script {
#[inline]
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let v = <&'a [u8]>::arbitrary(u)?;
Ok(Script::from_bytes(v))

View File

@ -56,6 +56,7 @@ impl ScriptHash {
/// > spend a P2SH output if the redemption script it refers to is >520 bytes in length.
///
/// ref: [BIP-16](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#user-content-520byte_limitation_on_serialized_script_size)
#[inline]
pub fn from_script(redeem_script: &Script) -> Result<Self, RedeemScriptSizeError> {
if redeem_script.len() > MAX_REDEEM_SCRIPT_SIZE {
return Err(RedeemScriptSizeError { size: redeem_script.len() });
@ -70,6 +71,7 @@ impl ScriptHash {
/// then the output will be unspendable (see [BIP-16]).
///
/// [BIP-16]: <https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#user-content-520byte_limitation_on_serialized_script_size>
#[inline]
pub fn from_script_unchecked(script: &Script) -> Self {
ScriptHash(hash160::Hash::hash(script.as_bytes()))
}
@ -84,6 +86,7 @@ impl WScriptHash {
/// > witnessScript must match the 32-byte witness program.
///
/// ref: [BIP-141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki)
#[inline]
pub fn from_script(witness_script: &Script) -> Result<Self, WitnessScriptSizeError> {
if witness_script.len() > MAX_WITNESS_SCRIPT_SIZE {
return Err(WitnessScriptSizeError { size: witness_script.len() });
@ -98,6 +101,7 @@ impl WScriptHash {
/// output then the output will be unspendable (see [BIP-141]).
///
/// ref: [BIP-141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki)
#[inline]
pub fn from_script_unchecked(script: &Script) -> Self {
WScriptHash(sha256::Hash::hash(script.as_bytes()))
}
@ -106,6 +110,7 @@ impl WScriptHash {
impl TryFrom<ScriptBuf> for ScriptHash {
type Error = RedeemScriptSizeError;
#[inline]
fn try_from(redeem_script: ScriptBuf) -> Result<Self, Self::Error> {
Self::from_script(&redeem_script)
}
@ -114,6 +119,7 @@ impl TryFrom<ScriptBuf> for ScriptHash {
impl TryFrom<&ScriptBuf> for ScriptHash {
type Error = RedeemScriptSizeError;
#[inline]
fn try_from(redeem_script: &ScriptBuf) -> Result<Self, Self::Error> {
Self::from_script(redeem_script)
}
@ -122,6 +128,7 @@ impl TryFrom<&ScriptBuf> for ScriptHash {
impl TryFrom<&Script> for ScriptHash {
type Error = RedeemScriptSizeError;
#[inline]
fn try_from(redeem_script: &Script) -> Result<Self, Self::Error> {
Self::from_script(redeem_script)
}
@ -130,6 +137,7 @@ impl TryFrom<&Script> for ScriptHash {
impl TryFrom<ScriptBuf> for WScriptHash {
type Error = WitnessScriptSizeError;
#[inline]
fn try_from(witness_script: ScriptBuf) -> Result<Self, Self::Error> {
Self::from_script(&witness_script)
}
@ -138,6 +146,7 @@ impl TryFrom<ScriptBuf> for WScriptHash {
impl TryFrom<&ScriptBuf> for WScriptHash {
type Error = WitnessScriptSizeError;
#[inline]
fn try_from(witness_script: &ScriptBuf) -> Result<Self, Self::Error> {
Self::from_script(witness_script)
}
@ -146,6 +155,7 @@ impl TryFrom<&ScriptBuf> for WScriptHash {
impl TryFrom<&Script> for WScriptHash {
type Error = WitnessScriptSizeError;
#[inline]
fn try_from(witness_script: &Script) -> Result<Self, Self::Error> {
Self::from_script(witness_script)
}
@ -159,10 +169,12 @@ pub struct RedeemScriptSizeError {
}
impl From<Infallible> for RedeemScriptSizeError {
#[inline]
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for RedeemScriptSizeError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "redeem script size exceeds {} bytes: {}", MAX_REDEEM_SCRIPT_SIZE, self.size)
}
@ -179,10 +191,12 @@ pub struct WitnessScriptSizeError {
}
impl From<Infallible> for WitnessScriptSizeError {
#[inline]
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for WitnessScriptSizeError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "witness script size exceeds {} bytes: {}", MAX_WITNESS_SCRIPT_SIZE, self.size)
}
@ -194,14 +208,17 @@ impl std::error::Error for WitnessScriptSizeError {}
// We keep all the `Script` and `ScriptBuf` impls together since its easier to see side-by-side.
impl From<ScriptBuf> for Box<Script> {
#[inline]
fn from(v: ScriptBuf) -> Self { v.into_boxed_script() }
}
impl From<ScriptBuf> for Cow<'_, Script> {
#[inline]
fn from(value: ScriptBuf) -> Self { Cow::Owned(value) }
}
impl<'a> From<Cow<'a, Script>> for ScriptBuf {
#[inline]
fn from(value: Cow<'a, Script>) -> Self {
match value {
Cow::Owned(owned) => owned,
@ -211,6 +228,7 @@ impl<'a> From<Cow<'a, Script>> for ScriptBuf {
}
impl<'a> From<Cow<'a, Script>> for Box<Script> {
#[inline]
fn from(value: Cow<'a, Script>) -> Self {
match value {
Cow::Owned(owned) => owned.into(),
@ -220,20 +238,24 @@ impl<'a> From<Cow<'a, Script>> for Box<Script> {
}
impl<'a> From<&'a Script> for Box<Script> {
#[inline]
fn from(value: &'a Script) -> Self { value.to_owned().into() }
}
impl<'a> From<&'a Script> for ScriptBuf {
#[inline]
fn from(value: &'a Script) -> Self { value.to_owned() }
}
impl<'a> From<&'a Script> for Cow<'a, Script> {
#[inline]
fn from(value: &'a Script) -> Self { Cow::Borrowed(value) }
}
/// Note: This will fail to compile on old Rust for targets that don't support atomics
#[cfg(target_has_atomic = "ptr")]
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`
@ -245,6 +267,7 @@ impl<'a> From<&'a Script> for Arc<Script> {
}
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`
@ -256,10 +279,12 @@ impl<'a> From<&'a Script> for Rc<Script> {
}
impl From<Vec<u8>> for ScriptBuf {
#[inline]
fn from(v: Vec<u8>) -> Self { ScriptBuf::from_bytes(v) }
}
impl From<ScriptBuf> for Vec<u8> {
#[inline]
fn from(v: ScriptBuf) -> Self { v.into_bytes() }
}
@ -269,6 +294,7 @@ impl AsRef<Script> for Script {
}
impl AsRef<Script> for ScriptBuf {
#[inline]
fn as_ref(&self) -> &Script { self }
}
@ -278,14 +304,17 @@ impl AsRef<[u8]> for Script {
}
impl AsRef<[u8]> for ScriptBuf {
#[inline]
fn as_ref(&self) -> &[u8] { self.as_bytes() }
}
impl AsMut<Script> for Script {
#[inline]
fn as_mut(&mut self) -> &mut Script { self }
}
impl AsMut<Script> for ScriptBuf {
#[inline]
fn as_mut(&mut self) -> &mut Script { self }
}
@ -295,6 +324,7 @@ impl AsMut<[u8]> for Script {
}
impl AsMut<[u8]> for ScriptBuf {
#[inline]
fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
}
@ -307,6 +337,7 @@ impl fmt::Debug for Script {
}
impl fmt::Debug for ScriptBuf {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self.as_script(), f) }
}
@ -389,6 +420,7 @@ impl fmt::Display for ScriptBuf {
}
impl fmt::LowerHex for Script {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
}
@ -404,6 +436,7 @@ impl fmt::LowerHex for ScriptBuf {
internals::impl_to_hex_from_lower_hex!(ScriptBuf, |script_buf: &ScriptBuf| script_buf.len() * 2);
impl fmt::UpperHex for Script {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
}
@ -415,28 +448,34 @@ impl fmt::UpperHex for ScriptBuf {
}
impl Borrow<Script> for ScriptBuf {
#[inline]
fn borrow(&self) -> &Script { self }
}
impl BorrowMut<Script> for ScriptBuf {
#[inline]
fn borrow_mut(&mut self) -> &mut Script { self }
}
impl PartialEq<ScriptBuf> for Script {
#[inline]
fn eq(&self, other: &ScriptBuf) -> bool { self.eq(other.as_script()) }
}
impl PartialEq<Script> for ScriptBuf {
#[inline]
fn eq(&self, other: &Script) -> bool { self.as_script().eq(other) }
}
impl PartialOrd<Script> for ScriptBuf {
#[inline]
fn partial_cmp(&self, other: &Script) -> Option<Ordering> {
self.as_script().partial_cmp(other)
}
}
impl PartialOrd<ScriptBuf> for Script {
#[inline]
fn partial_cmp(&self, other: &ScriptBuf) -> Option<Ordering> {
self.partial_cmp(other.as_script())
}

View File

@ -28,17 +28,21 @@ impl ScriptBuf {
/// Converts byte vector into script.
///
/// This method doesn't (re)allocate.
#[inline]
pub const fn from_bytes(bytes: Vec<u8>) -> Self { ScriptBuf(bytes) }
/// Returns a reference to unsized script.
#[inline]
pub fn as_script(&self) -> &Script { Script::from_bytes(&self.0) }
/// Returns a mutable reference to unsized script.
#[inline]
pub fn as_mut_script(&mut self) -> &mut Script { Script::from_bytes_mut(&mut self.0) }
/// Converts the script into a byte vector.
///
/// This method doesn't (re)allocate.
#[inline]
pub fn into_bytes(self) -> Vec<u8> { self.0 }
/// Converts this `ScriptBuf` into a [boxed](Box) [`Script`].
@ -56,6 +60,7 @@ impl ScriptBuf {
}
/// Constructs a new empty script with pre-allocated capacity.
#[inline]
pub fn with_capacity(capacity: usize) -> Self { ScriptBuf::from_bytes(Vec::with_capacity(capacity)) }
/// Pre-allocates at least `additional_len` bytes if needed.
@ -68,6 +73,7 @@ impl ScriptBuf {
/// # Panics
///
/// Panics if the new capacity exceeds `isize::MAX bytes`.
#[inline]
pub fn reserve(&mut self, additional_len: usize) { self.0.reserve(additional_len); }
/// Pre-allocates exactly `additional_len` bytes if needed.
@ -83,21 +89,25 @@ impl ScriptBuf {
/// # Panics
///
/// Panics if the new capacity exceeds `isize::MAX bytes`.
#[inline]
pub fn reserve_exact(&mut self, additional_len: usize) { self.0.reserve_exact(additional_len); }
}
impl Deref for ScriptBuf {
type Target = Script;
#[inline]
fn deref(&self) -> &Self::Target { self.as_script() }
}
impl DerefMut for ScriptBuf {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_script() }
}
#[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for ScriptBuf {
#[inline]
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let v = Vec::<u8>::arbitrary(u)?;
Ok(ScriptBuf::from_bytes(v))