Skip to content

Commit

Permalink
Merge pull request #176 from danielhenrymantilla/main
Browse files Browse the repository at this point in the history
Offer (opt-in) `const-generic` mappings. Mainly, a `U<N>` type alias.
  • Loading branch information
paholg committed Dec 5, 2022
2 parents d3b30c8 + cf9f811 commit 4ce4473
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 12 deletions.
10 changes: 8 additions & 2 deletions .github/workflows/check.yml
Expand Up @@ -21,6 +21,12 @@ jobs:
- stable
- beta
- nightly
mb_const_generics:
- ""
- "--features const-generics"
exclude:
- mb_const_generics: "--features const-generics"
rust: 1.37.0
include:
- os: macos-latest
rust: stable
Expand All @@ -36,11 +42,11 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --features "strict"
args: --verbose --features "strict" ${{ matrix.mb_const_generics }}
- uses: actions-rs/cargo@v1
with:
command: doc
args: --features "strict"
args: --features "strict" ${{ matrix.mb_const_generics }}

clippy:
name: clippy + fmt
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -28,4 +28,5 @@ scale-info = { version = "1.0", default-features = false, optional = true }
i128 = []
strict = []
force_unix_path_separator = []
const-generics = []
scale_info = ["scale-info/derive"]
91 changes: 91 additions & 0 deletions build/generic_const_mappings.rs
@@ -0,0 +1,91 @@
use super::*;

pub fn emit_impls() -> ::std::io::Result<()> {
let out_dir = ::std::env::var("OUT_DIR").unwrap();
let dest = ::std::path::Path::new(&out_dir).join("generic_const_mappings.rs");
println!(
"cargo:rustc-env=TYPENUM_BUILD_GENERIC_CONSTS={}",
dest.display()
);
let mut f = ::std::fs::File::create(&dest).unwrap();

#[allow(clippy::write_literal)]
write!(f, "{}", "\
#[cfg(doc)]
use generic_const_mappings::*;
/// Module with some `const`-generics-friendly definitions, to help bridge the gap
/// between those and `typenum` types.
///
/// - It requires the `const-generics` crate feature to be enabled.
///
/// The main type to use here is [`U`], although [`Const`] and [`ToUInt`] may be needed
/// in a generic context.
#[allow(warnings)] // script-generated code
pub mod generic_const_mappings {
use crate::*;
/// The main mapping from a generic `const: usize` to a [`UInt`]: [`U<N>`] is expected to work like [`UN`].
///
/// - It requires the `const-generics` crate feature to be enabled.
///
/// [`U<N>`]: `U`
/// [`UN`]: `U42`
///
/// # Example
///
/// ```rust
/// use typenum::*;
///
/// assert_type_eq!(U<42>, U42);
/// ```
///
/// This can even be used in a generic `const N: usize` context, provided the
/// genericity is guarded by a `where` clause:
///
/// ```rust
/// use typenum::*;
///
/// struct MyStruct<const N: usize>;
///
/// trait MyTrait { type AssocType; }
///
/// impl<const N: usize> MyTrait
/// for MyStruct<N>
/// where
/// Const<N> : ToUInt,
/// {
/// type AssocType = U<N>;
/// }
///
/// assert_type_eq!(<MyStruct<42> as MyTrait>::AssocType, U42);
/// ```
pub type U<const N: usize> = <Const<N> as ToUInt>::Output;
/// Used to allow the usage of [`U`] in a generic context.
pub struct Const<const N: usize>;
/// Used to allow the usage of [`U`] in a generic context.
pub trait ToUInt {
/// The [`UN`][`crate::U42`] type corresponding to `Self = Const<N>`.
type Output;
}
\
")?;

for uint in uints() {
write!(
f,
"
impl ToUInt for Const<{uint}> {{
type Output = U{uint};
}}
\
",
uint = uint,
)?;
}
write!(f, "}}")?;
f.flush()?;
Ok(())
}
26 changes: 17 additions & 9 deletions build/main.rs
Expand Up @@ -4,6 +4,8 @@ use std::fs::File;
use std::io::Write;
use std::path::Path;

#[cfg(feature = "const-generics")]
mod generic_const_mappings;
mod op;
mod tests;

Expand Down Expand Up @@ -75,19 +77,22 @@ pub fn gen_int(i: i64) -> IntCode {
)]
pub fn no_std() {}

// fixme: get a warning when testing without this
#[allow(dead_code)]
fn main() {
let highest: u64 = 1024;

const HIGHEST: u64 = 1024;
fn uints() -> impl Iterator<Item = u64> {
// Use hardcoded values to avoid issues with cross-compilation.
// See https://github.com/paholg/typenum/issues/162
let first2: u32 = 11; // (highest as f64).log(2.0).round() as u32 + 1;
let first10: u32 = 4; // (highest as f64).log(10.0) as u32 + 1;
let uints = (0..(highest + 1))
(0..(HIGHEST + 1))
.chain((first2..64).map(|i| 2u64.pow(i)))
.chain((first10..20).map(|i| 10u64.pow(i)));
.chain((first10..20).map(|i| 10u64.pow(i)))
}

// fixme: get a warning when testing without this
#[allow(dead_code)]
fn main() {
println!("cargo:rerun-if-changed=build/main.rs"); // Allow caching the generation if `src/*` files change.

let out_dir = env::var("OUT_DIR").unwrap();
let dest = Path::new(&out_dir).join("consts.rs");
#[cfg(not(feature = "force_unix_path_separator"))]
Expand Down Expand Up @@ -163,11 +168,11 @@ pub mod consts {{
pub type True = B1;
pub type False = B0;
",
highest = highest
highest = HIGHEST,
)
.unwrap();

for u in uints {
for u in uints() {
writeln!(f, " pub type U{} = {};", u, gen_uint(u)).unwrap();
if u <= ::std::i64::MAX as u64 && u != 0 {
let i = u as i64;
Expand All @@ -184,4 +189,7 @@ pub mod consts {{
tests::build_tests().unwrap();

op::write_op_macro().unwrap();

#[cfg(feature = "const-generics")]
generic_const_mappings::emit_impls().unwrap();
}
20 changes: 19 additions & 1 deletion src/lib.rs
Expand Up @@ -71,12 +71,16 @@ use core::cmp::Ordering;
mod generated {
include!(concat!(env!("OUT_DIR"), "/op.rs"));
include!(concat!(env!("OUT_DIR"), "/consts.rs"));
#[cfg(feature = "const-generics")]
include!(concat!(env!("OUT_DIR"), "/generic_const_mappings.rs"));
}

#[cfg(not(feature = "force_unix_path_separator"))]
mod generated {
include!(env!("TYPENUM_BUILD_OP"));
include!(env!("TYPENUM_BUILD_CONSTS"));
#[cfg(feature = "const-generics")]
include!(env!("TYPENUM_BUILD_GENERIC_CONSTS"));
}

pub mod bit;
Expand All @@ -91,7 +95,6 @@ pub mod array;

pub use crate::{
array::{ATerm, TArr},
consts::*,
generated::consts,
int::{NInt, PInt},
marker_traits::*,
Expand All @@ -100,6 +103,21 @@ pub use crate::{
uint::{UInt, UTerm},
};

#[doc(no_inline)]
#[rustfmt::skip]
pub use consts::{
False, True, B0, B1,
U0, U1, U2, *,
N1, N2, Z0, P1, P2, *,
};

#[cfg(feature = "const-generics")]
pub use crate::generated::generic_const_mappings;

#[cfg(feature = "const-generics")]
#[doc(no_inline)]
pub use generic_const_mappings::{Const, ToUInt, U};

/// A potential output from `Cmp`, this is the type equivalent to the enum variant
/// `core::cmp::Ordering::Greater`.
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)]
Expand Down

0 comments on commit 4ce4473

Please sign in to comment.