summaryrefslogtreecommitdiffstats
path: root/vendor/typenum/build/main.rs
blob: 68a97af82164c9f4bef07477ef3eca7096ea5125 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
use std::env;
use std::fmt;
use std::fs::File;
use std::io::Write;
use std::path::Path;

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

pub enum UIntCode {
    Term,
    Zero(Box<UIntCode>),
    One(Box<UIntCode>),
}

pub enum IntCode {
    Zero,
    Pos(Box<UIntCode>),
    Neg(Box<UIntCode>),
}

impl fmt::Display for UIntCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            UIntCode::Term => write!(f, "UTerm"),
            UIntCode::Zero(ref inner) => write!(f, "UInt<{}, B0>", inner),
            UIntCode::One(ref inner) => write!(f, "UInt<{}, B1>", inner),
        }
    }
}

impl fmt::Display for IntCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IntCode::Zero => write!(f, "Z0"),
            IntCode::Pos(ref inner) => write!(f, "PInt<{}>", inner),
            IntCode::Neg(ref inner) => write!(f, "NInt<{}>", inner),
        }
    }
}

pub fn gen_uint(u: u64) -> UIntCode {
    let mut result = UIntCode::Term;
    let mut x = 1u64 << 63;
    while x > u {
        x >>= 1
    }
    while x > 0 {
        result = if x & u > 0 {
            UIntCode::One(Box::new(result))
        } else {
            UIntCode::Zero(Box::new(result))
        };
        x >>= 1;
    }
    result
}

pub fn gen_int(i: i64) -> IntCode {
    use std::cmp::Ordering::{Equal, Greater, Less};

    match i.cmp(&0) {
        Greater => IntCode::Pos(Box::new(gen_uint(i as u64))),
        Less => IntCode::Neg(Box::new(gen_uint(i.abs() as u64))),
        Equal => IntCode::Zero,
    }
}

#[cfg_attr(
    feature = "no_std",
    deprecated(
        since = "1.3.0",
        note = "the `no_std` flag is no longer necessary and will be removed in the future"
    )
)]
pub fn no_std() {}

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;
    (0..(HIGHEST + 1))
        .chain((first2..64).map(|i| 2u64.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"))]
    println!("cargo:rustc-env=TYPENUM_BUILD_CONSTS={}", dest.display());

    let mut f = File::create(&dest).unwrap();

    no_std();

    // Header stuff here!
    write!(
        f,
        "
/**
Type aliases for many constants.

This file is generated by typenum's build script.

For unsigned integers, the format is `U` followed by the number. We define aliases for

- Numbers 0 through {highest}
- Powers of 2 below `u64::MAX`
- Powers of 10 below `u64::MAX`

These alias definitions look like this:

```rust
use typenum::{{B0, B1, UInt, UTerm}};

# #[allow(dead_code)]
type U6 = UInt<UInt<UInt<UTerm, B1>, B1>, B0>;
```

For positive signed integers, the format is `P` followed by the number and for negative
signed integers it is `N` followed by the number. For the signed integer zero, we use
`Z0`. We define aliases for

- Numbers -{highest} through {highest}
- Powers of 2 between `i64::MIN` and `i64::MAX`
- Powers of 10 between `i64::MIN` and `i64::MAX`

These alias definitions look like this:

```rust
use typenum::{{B0, B1, UInt, UTerm, PInt, NInt}};

# #[allow(dead_code)]
type P6 = PInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>>;
# #[allow(dead_code)]
type N6 = NInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>>;
```

# Example
```rust
# #[allow(unused_imports)]
use typenum::{{U0, U1, U2, U3, U4, U5, U6}};
# #[allow(unused_imports)]
use typenum::{{N3, N2, N1, Z0, P1, P2, P3}};
# #[allow(unused_imports)]
use typenum::{{U774, N17, N10000, P1024, P4096}};
```

We also define the aliases `False` and `True` for `B0` and `B1`, respectively.
*/
#[allow(missing_docs)]
pub mod consts {{
    use crate::uint::{{UInt, UTerm}};
    use crate::int::{{PInt, NInt}};

    pub use crate::bit::{{B0, B1}};
    pub use crate::int::Z0;

    pub type True = B1;
    pub type False = B0;
",
        highest = HIGHEST,
    )
    .unwrap();

    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;
            writeln!(
                f,
                "    pub type P{i} = PInt<U{i}>; pub type N{i} = NInt<U{i}>;",
                i = i
            )
            .unwrap();
        }
    }
    write!(f, "}}").unwrap();

    tests::build_tests().unwrap();

    op::write_op_macro().unwrap();

    #[cfg(feature = "const-generics")]
    generic_const_mappings::emit_impls().unwrap();
}