units: extend op reference macro to handle generics and where clauses

This is a bit ugly and requires that we put our where-clauses in
parentheses because the macro_rules parser sucks, but it allows us to
move the blanket-impls on NumOpResult into the macro.

This commit moves one instance and updates the macro; the next commits
will change the rest.
This commit is contained in:
Andrew Poelstra 2025-02-18 19:58:15 +00:00
parent ad9564895b
commit 21ac5aefe0
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
2 changed files with 31 additions and 58 deletions

View File

@ -246,6 +246,20 @@ crate::internal_macros::impl_op_for_references! {
fn rem(self, modulus: i64) -> Self::Output { self.checked_rem(modulus).valid_or_error() }
}
impl<T> ops::Add<NumOpResult<T>> for NumOpResult<T>
where
(T: Copy + ops::Add<Output = NumOpResult<T>>)
{
type Output = NumOpResult<T>;
fn add(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(R::Valid(lhs), R::Valid(rhs)) => lhs + rhs,
(_, _) => R::Error(NumOpError {}),
}
}
}
}
impl ops::Neg for SignedAmount {
@ -254,59 +268,6 @@ impl ops::Neg for SignedAmount {
fn neg(self) -> Self::Output { Self::from_sat(self.to_sat().neg()) }
}
impl<T> ops::Add for NumOpResult<T>
where
T: ops::Add<Output = NumOpResult<T>>,
{
type Output = NumOpResult<T>;
fn add(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(R::Valid(lhs), R::Valid(rhs)) => lhs + rhs,
(_, _) => R::Error(NumOpError {}),
}
}
}
impl<T> ops::Add<NumOpResult<T>> for &NumOpResult<T>
where
T: ops::Add<Output = NumOpResult<T>> + Copy,
{
type Output = NumOpResult<T>;
fn add(self, rhs: NumOpResult<T>) -> Self::Output {
match (self, rhs) {
(R::Valid(lhs), R::Valid(rhs)) => *lhs + rhs,
(_, _) => R::Error(NumOpError {}),
}
}
}
impl<T> ops::Add<&NumOpResult<T>> for NumOpResult<T>
where
T: ops::Add<Output = NumOpResult<T>> + Copy,
{
type Output = NumOpResult<T>;
fn add(self, rhs: &NumOpResult<T>) -> Self::Output {
match (self, rhs) {
(R::Valid(lhs), R::Valid(rhs)) => lhs + *rhs,
(_, _) => R::Error(NumOpError {}),
}
}
}
impl<T> ops::Add for &NumOpResult<T>
where
T: ops::Add<Output = NumOpResult<T>> + Copy,
{
type Output = NumOpResult<T>;
fn add(self, rhs: &NumOpResult<T>) -> Self::Output {
match (self, rhs) {
(R::Valid(lhs), R::Valid(rhs)) => *lhs + *rhs,
(_, _) => R::Error(NumOpError {}),
}
}
}
impl<T> ops::Sub for NumOpResult<T>
where
T: ops::Sub<Output = NumOpResult<T>>,

View File

@ -17,37 +17,49 @@
///
/// You must specify `$other_ty` and you may not use `Self`. So e.g. you need
/// to write `impl ops::Add<Amount> for Amount { ... }` when calling this macro.
///
/// Your where clause must include extra parenthesis, like `where (T: Copy)`.
macro_rules! impl_op_for_references {
($(
impl $($op_trait:ident)::+<$other_ty:ty> for $ty:ty {
impl$(<$gen:ident>)? $($op_trait:ident)::+<$other_ty:ty> for $ty:ty
$(where ($($bounds:tt)*))?
{
type Output = $($main_output:ty)*;
fn $op:ident($($main_args:tt)*) -> Self::Output {
$($main_impl:tt)*
}
}
)+) => {$(
impl $($op_trait)::+<$other_ty> for $ty {
impl$(<$gen>)? $($op_trait)::+<$other_ty> for $ty
$(where $($bounds)*)?
{
type Output = $($main_output)*;
fn $op($($main_args)*) -> Self::Output {
$($main_impl)*
}
}
impl $($op_trait)::+<$other_ty> for &$ty {
impl$(<$gen>)? $($op_trait)::+<$other_ty> for &$ty
$(where $($bounds)*)?
{
type Output = <$ty as $($op_trait)::+<$other_ty>>::Output;
fn $op(self, rhs: $other_ty) -> Self::Output {
(*self).$op(rhs)
}
}
impl $($op_trait)::+<&$other_ty> for $ty {
impl$(<$gen>)? $($op_trait)::+<&$other_ty> for $ty
$(where $($bounds)*)?
{
type Output = <$ty as $($op_trait)::+<$other_ty>>::Output;
fn $op(self, rhs: &$other_ty) -> Self::Output {
self.$op(*rhs)
}
}
impl<'a> $($op_trait)::+<&'a $other_ty> for &$ty {
impl<'a, $($gen)?> $($op_trait)::+<&'a $other_ty> for &$ty
$(where $($bounds)*)?
{
type Output = <$ty as $($op_trait)::+<$other_ty>>::Output;
fn $op(self, rhs: &$other_ty) -> Self::Output {
(*self).$op(*rhs)