From 3e2807018764740d273befc81f53d18228cb39dd Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 17 Nov 2022 10:33:38 +1100 Subject: [PATCH] Duplicate impl_array_newtype The two crates `secp256k1` and `secp256k1-sys` serve very different purposes, having a macro defined in one that is used in both makes it hard to get nuanced things correct in the macro, for example the comparison implementations (`Ord`, `PartialEq` etc.) are semantically different in each crate. In an effort to decouple `secp256k1` and `secp256k1-sys` duplicate the `impl_array_newtype` macro. --- src/key.rs | 4 +- src/lib.rs | 2 +- src/macros.rs | 107 +++++++++++++++++++++++++++++++++++++++++++++++++ src/schnorr.rs | 4 +- 4 files changed, 112 insertions(+), 5 deletions(-) diff --git a/src/key.rs b/src/key.rs index 8832c99..6b67c67 100644 --- a/src/key.rs +++ b/src/key.rs @@ -24,11 +24,11 @@ use core::{fmt, ptr, str}; use serde::ser::SerializeTuple; use crate::ffi::types::c_uint; -use crate::ffi::{self, impl_array_newtype, CPtr}; +use crate::ffi::{self, CPtr}; #[cfg(all(feature = "global-context", feature = "rand-std"))] use crate::schnorr; use crate::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey}; -use crate::{constants, from_hex, Scalar, Secp256k1, Signing, Verification}; +use crate::{constants, from_hex, impl_array_newtype, Scalar, Secp256k1, Signing, Verification}; #[cfg(feature = "global-context")] use crate::{ecdsa, Message, SECP256K1}; #[cfg(feature = "bitcoin-hashes")] diff --git a/src/lib.rs b/src/lib.rs index db3faa3..6a334d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -200,7 +200,7 @@ pub use serde; pub use crate::context::*; use crate::ffi::types::AlignedType; -use crate::ffi::{impl_array_newtype, CPtr}; +use crate::ffi::CPtr; #[cfg(feature = "bitcoin-hashes")] use crate::hashes::Hash; pub use crate::key::{PublicKey, SecretKey, *}; diff --git a/src/macros.rs b/src/macros.rs index d2da41b..fbeb6b7 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -13,6 +13,113 @@ // If not, see . // +/// Implement methods and traits for types that contain an inner array. +#[macro_export] +macro_rules! impl_array_newtype { + ($thing:ident, $ty:ty, $len:expr) => { + impl Copy for $thing {} + + impl $thing { + /// Converts the object to a raw pointer for FFI interfacing. + #[inline] + pub fn as_ptr(&self) -> *const $ty { + let &$thing(ref dat) = self; + dat.as_ptr() + } + + /// Converts the object to a mutable raw pointer for FFI interfacing. + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut $ty { + let &mut $thing(ref mut dat) = self; + dat.as_mut_ptr() + } + + /// Returns the length of the object as an array. + #[inline] + pub fn len(&self) -> usize { $len } + + /// Returns whether the object as an array is empty. + #[inline] + pub fn is_empty(&self) -> bool { false } + } + + impl AsRef<[$ty; $len]> for $thing { + #[inline] + /// Gets a reference to the underlying array + fn as_ref(&self) -> &[$ty; $len] { + let &$thing(ref dat) = self; + dat + } + } + + impl PartialEq for $thing { + #[inline] + fn eq(&self, other: &$thing) -> bool { + &self[..] == &other[..] + } + } + + impl Eq for $thing {} + + impl ::core::hash::Hash for $thing { + fn hash(&self, state: &mut H) { + (&self[..]).hash(state) + } + } + + impl PartialOrd for $thing { + #[inline] + fn partial_cmp(&self, other: &$thing) -> Option { + self[..].partial_cmp(&other[..]) + } + } + + impl Ord for $thing { + #[inline] + fn cmp(&self, other: &$thing) -> core::cmp::Ordering { + self[..].cmp(&other[..]) + } + } + + impl Clone for $thing { + #[inline] + fn clone(&self) -> $thing { + let &$thing(ref dat) = self; + $thing(dat.clone()) + } + } + + impl core::ops::Index for $thing + where + [$ty]: core::ops::Index, + { + type Output = <[$ty] as core::ops::Index>::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { &self.0[index] } + } + + impl $crate::CPtr for $thing { + type Target = $ty; + fn as_c_ptr(&self) -> *const Self::Target { + if self.is_empty() { + core::ptr::null() + } else { + self.as_ptr() + } + } + + fn as_mut_c_ptr(&mut self) -> *mut Self::Target { + if self.is_empty() { + core::ptr::null::() as *mut _ + } else { + self.as_mut_ptr() + } + } + } + } +} + macro_rules! impl_pretty_debug { ($thing:ident) => { impl core::fmt::Debug for $thing { diff --git a/src/schnorr.rs b/src/schnorr.rs index 0d001e7..2d33ce9 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -7,11 +7,11 @@ use core::{fmt, ptr, str}; #[cfg(any(test, feature = "rand"))] use rand::{CryptoRng, Rng}; -use crate::ffi::{self, impl_array_newtype, CPtr}; +use crate::ffi::{self, CPtr}; use crate::key::{KeyPair, XOnlyPublicKey}; #[cfg(all(feature = "global-context", feature = "rand-std"))] use crate::SECP256K1; -use crate::{constants, from_hex, Error, Message, Secp256k1, Signing, Verification}; +use crate::{constants, from_hex, impl_array_newtype, Error, Message, Secp256k1, Signing, Verification}; /// Represents a Schnorr signature. pub struct Signature([u8; constants::SCHNORR_SIGNATURE_SIZE]);