-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add optional typenum-macro that provides tyint and tyuint (#136)
Both tyint tyuint are convenient macros to convert integer literals into typenum types.
- Loading branch information
1 parent
932263f
commit 76a3d36
Showing
6 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/// Generates a signed typenum from a signed integer literal. | ||
/// | ||
/// The output type can be either [PInt](typenum::PInt), [NInt](typenum::NInt) or [Z0](typenum::Z0), | ||
/// (e.g., [P1](typenum::P1), [N2](typenum::N2)) depending on the value of input literal. | ||
/// | ||
/// ```rust | ||
/// use typenum::{tyint, N2, P1, Z0}; | ||
/// let _: tyint!(0) = Z0::new(); | ||
/// let _: tyint!(1) = P1::new(); | ||
/// let _: tyint!(-2) = N2::new(); | ||
/// ``` | ||
pub use typenum_macro::tyint; | ||
|
||
/// Generates an unsigned typenum from an unsigned integer literal. | ||
/// | ||
/// The output type can be either [UTerm](typenum::UTerm) or [UInt](typenum::UInt) | ||
/// (e.g., [U0](typenum::U0), [U1](typenum::U1)) depending on the value of input literal. | ||
/// | ||
/// ```rust | ||
/// use typenum::{tyuint, U0, U1, U2}; | ||
/// let _: tyuint!(0) = U0::new(); | ||
/// let _: tyuint!(1) = U1::new(); | ||
/// let _: tyuint!(2) = U2::new(); | ||
/// ``` | ||
pub use typenum_macro::tyuint; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#![cfg(feature = "macros")] | ||
#![no_std] | ||
|
||
extern crate typenum; | ||
|
||
use core::marker::PhantomData; | ||
use typenum::{ | ||
consts::*, | ||
macros::{tyint, tyuint}, | ||
}; | ||
|
||
struct Same<Lhs, Rhs> { | ||
_phantom: PhantomData<(Lhs, Rhs)>, | ||
} | ||
|
||
impl<T> Same<T, T> { | ||
pub fn new() -> Self { | ||
Self { | ||
_phantom: PhantomData, | ||
} | ||
} | ||
} | ||
|
||
type Positive0 = tyint!(0); | ||
type Positive1 = tyint!(1); | ||
type Positive2 = tyint!(2); | ||
type Positive3 = tyint!(3); | ||
type Positive4 = tyint!(4); | ||
type Positive4294967296 = tyint!(4294967296); | ||
|
||
type Negative0 = tyint!(-0); | ||
type Negative1 = tyint!(-1); | ||
type Negative2 = tyint!(-2); | ||
type Negative3 = tyint!(-3); | ||
type Negative4 = tyint!(-4); | ||
type Negative4294967296 = tyint!(-4294967296); | ||
|
||
type Unsigned0 = tyuint!(0); | ||
type Unsigned1 = tyuint!(1); | ||
type Unsigned2 = tyuint!(2); | ||
type Unsigned3 = tyuint!(3); | ||
type Unsigned4 = tyuint!(4); | ||
type Unsigned4294967296 = tyuint!(4294967296); | ||
|
||
#[test] | ||
fn tyint_test() { | ||
let _ = Same::<Positive0, Z0>::new(); | ||
let _ = Same::<Positive1, P1>::new(); | ||
let _ = Same::<Positive2, P2>::new(); | ||
let _ = Same::<Positive3, P3>::new(); | ||
let _ = Same::<Positive4, P4>::new(); | ||
let _ = Same::<Positive4294967296, P4294967296>::new(); | ||
|
||
let _ = Same::<Negative0, Z0>::new(); | ||
let _ = Same::<Negative1, N1>::new(); | ||
let _ = Same::<Negative2, N2>::new(); | ||
let _ = Same::<Negative3, N3>::new(); | ||
let _ = Same::<Negative4, N4>::new(); | ||
let _ = Same::<Negative4294967296, N4294967296>::new(); | ||
|
||
let _ = Same::<Unsigned0, U0>::new(); | ||
let _ = Same::<Unsigned1, U1>::new(); | ||
let _ = Same::<Unsigned2, U2>::new(); | ||
let _ = Same::<Unsigned3, U3>::new(); | ||
let _ = Same::<Unsigned4, U4>::new(); | ||
let _ = Same::<Unsigned4294967296, U4294967296>::new(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "typenum-macro" | ||
version = "0.1.0" | ||
authors = ["jerry73204 <[email protected]>"] | ||
edition = "2018" | ||
|
||
[lib] | ||
proc-macro = true | ||
|
||
[dependencies] | ||
syn = "1.0" | ||
quote = "1.0" | ||
proc-macro2 = "1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
#![no_std] | ||
|
||
extern crate proc_macro; | ||
|
||
use proc_macro::TokenStream; | ||
use proc_macro2::TokenStream as TokenStream2; | ||
use quote::quote; | ||
use syn::{ | ||
parse::{Parse, ParseStream, Result as ParseResult}, | ||
parse_macro_input, LitInt, Token, | ||
}; | ||
|
||
struct SignedInteger { | ||
has_negative_op: bool, | ||
value: u128, | ||
} | ||
|
||
impl Parse for SignedInteger { | ||
fn parse(input: ParseStream) -> ParseResult<Self> { | ||
let has_negative_op = if input.peek(Token![-]) { | ||
input.parse::<Token![-]>()?; | ||
true | ||
} else { | ||
false | ||
}; | ||
|
||
let literal = input.parse::<LitInt>()?; | ||
let value = literal.base10_parse::<u128>()?; | ||
|
||
let output = SignedInteger { | ||
has_negative_op, | ||
value, | ||
}; | ||
|
||
Ok(output) | ||
} | ||
} | ||
|
||
struct UnsignedInteger { | ||
value: u128, | ||
} | ||
|
||
impl Parse for UnsignedInteger { | ||
fn parse(input: ParseStream) -> ParseResult<Self> { | ||
let literal = input.parse::<LitInt>()?; | ||
let value = literal.base10_parse::<u128>()?; | ||
|
||
let output = UnsignedInteger { value }; | ||
|
||
Ok(output) | ||
} | ||
} | ||
|
||
#[proc_macro] | ||
pub fn tyint(input: TokenStream) -> TokenStream { | ||
let SignedInteger { | ||
has_negative_op, | ||
value, | ||
} = parse_macro_input!(input as SignedInteger); | ||
|
||
let tokens = if value == 0 { | ||
quote! { | ||
typenum::consts::Z0 | ||
} | ||
} else if has_negative_op { | ||
let uint_tokens = recursive_value_to_typeuint(value); | ||
quote! { | ||
typenum::int::NInt<#uint_tokens> | ||
} | ||
} else { | ||
let uint_tokens = recursive_value_to_typeuint(value); | ||
quote! { | ||
typenum::int::PInt<#uint_tokens> | ||
} | ||
}; | ||
|
||
TokenStream::from(tokens) | ||
} | ||
|
||
#[proc_macro] | ||
pub fn tyuint(input: TokenStream) -> TokenStream { | ||
let UnsignedInteger { value } = parse_macro_input!(input as UnsignedInteger); | ||
|
||
let tokens = recursive_value_to_typeuint(value); | ||
TokenStream::from(tokens) | ||
} | ||
|
||
fn recursive_value_to_typeuint(value: u128) -> TokenStream2 { | ||
if value == 0 { | ||
quote! { | ||
typenum::uint::UTerm | ||
} | ||
} else if value & 1 == 1 { | ||
let sub_tokens = recursive_value_to_typeuint(value >> 1); | ||
quote! { | ||
typenum::uint::UInt<#sub_tokens, typenum::bit::B1> | ||
} | ||
} else { | ||
let sub_tokens = recursive_value_to_typeuint(value >> 1); | ||
quote! { | ||
typenum::uint::UInt<#sub_tokens, typenum::bit::B0> | ||
} | ||
} | ||
} |