Skip to content

Commit

Permalink
Merge #55
Browse files Browse the repository at this point in the history
55: Add derive macro for num_traits::Signed r=cuviper a=tdelabro



Co-authored-by: Timothée Delabrouille <timothee.delabrouille@gmail.com>
Co-authored-by: Josh Stone <cuviper@gmail.com>
  • Loading branch information
3 people authored Oct 7, 2023
2 parents 38d08c8 + 3329097 commit 2c5013e
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 1 deletion.
58 changes: 58 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -952,3 +952,61 @@ pub fn float(input: TokenStream) -> TokenStream {

import.wrap("Float", name, impl_).into()
}

/// Derives [`num_traits::Signed`][signed] for newtypes. The inner type must already implement
/// `Signed`.
///
/// [signed]: https://docs.rs/num-traits/0.2/num_traits/sign/trait.Signed.html
#[proc_macro_derive(Signed, attributes(num_traits))]
pub fn signed(input: TokenStream) -> TokenStream {
let ast = parse!(input as syn::DeriveInput);
let name = &ast.ident;
let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);

let import = NumTraits::new(&ast);

let impl_ = quote! {
impl #import::Signed for #name {
#[inline]
fn abs(&self) -> Self {
#name(<#inner_ty as #import::Signed>::abs(&self.0))
}
#[inline]
fn abs_sub(&self, other: &Self) -> Self {
#name(<#inner_ty as #import::Signed>::abs_sub(&self.0, &other.0))
}
#[inline]
fn signum(&self) -> Self {
#name(<#inner_ty as #import::Signed>::signum(&self.0))
}
#[inline]
fn is_positive(&self) -> bool {
<#inner_ty as #import::Signed>::is_positive(&self.0)
}
#[inline]
fn is_negative(&self) -> bool {
<#inner_ty as #import::Signed>::is_negative(&self.0)
}
}
};

import.wrap("Signed", &name, impl_).into()
}

/// Derives [`num_traits::Unsigned`][unsigned]. The inner type must already implement
/// `Unsigned`.
///
/// [unsigned]: https://docs.rs/num/latest/num/traits/trait.Unsigned.html
#[proc_macro_derive(Unsigned, attributes(num_traits))]
pub fn unsigned(input: TokenStream) -> TokenStream {
let ast = parse!(input as syn::DeriveInput);
let name = &ast.ident;

let import = NumTraits::new(&ast);

let impl_ = quote! {
impl #import::Unsigned for #name {}
};

import.wrap("Unsigned", &name, impl_).into()
}
21 changes: 20 additions & 1 deletion tests/newtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,22 @@ extern crate num as num_renamed;
#[macro_use]
extern crate num_derive;

use crate::num_renamed::{Float, FromPrimitive, Num, NumCast, One, ToPrimitive, Zero};
use crate::num_renamed::{
Float, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Unsigned, Zero,
};
use std::ops::Neg;

#[derive(PartialEq, Zero, One, NumOps, Num, Unsigned)]
struct MyNum(u32);

#[test]
fn test_derive_unsigned_works() {
fn do_nothing_on_unsigned(_input: impl Unsigned) {}

let x = MyNum(42);
do_nothing_on_unsigned(x);
}

#[derive(
Debug,
Clone,
Expand All @@ -19,6 +32,7 @@ use std::ops::Neg;
Zero,
Num,
Float,
Signed,
)]
struct MyFloat(f64);

Expand Down Expand Up @@ -87,3 +101,8 @@ fn test_num() {
fn test_float() {
assert_eq!(MyFloat(4.0).log(MyFloat(2.0)), MyFloat(2.0));
}

#[test]
fn test_signed() {
assert!(MyFloat(-2.0).is_negative())
}

0 comments on commit 2c5013e

Please sign in to comment.