Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offer (opt-in) const-generic mappings. Mainly, a U<N> type alias. #176

Merged
merged 5 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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, *,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: re-export the negative numbers in the right order:

Suggested change
N1, N2, Z0, P1, P2, *,
N2, N1, 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