Skip to content

Commit cfc416e

Browse files
committed
Implement 8 and optionally 16 bit integers with build.rs generated enum
1 parent ebe62f8 commit cfc416e

File tree

4 files changed

+209
-2
lines changed

4 files changed

+209
-2
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ license = "MIT OR Apache-2.0"
1414
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1515

1616
[features]
17+
enum_repr_16 = []
1718
default = ["std"]
1819
std = []
1920

build.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
use std::io::{BufWriter, Result, Write};
2+
3+
#[derive(Clone, Copy)]
4+
enum BitInfo {
5+
Unsigned {
6+
prim_max: u64,
7+
},
8+
Signed {
9+
signed_max: i64,
10+
signed_min: i64,
11+
prim_max: i64,
12+
},
13+
}
14+
15+
struct EnumInfo {
16+
ty_name: &'static str,
17+
name: &'static str,
18+
bit_info: BitInfo,
19+
}
20+
21+
const FILES: &[EnumInfo] = &[
22+
EnumInfo {
23+
ty_name: "u8",
24+
name: "u8_repr.rs",
25+
bit_info: BitInfo::Unsigned {
26+
prim_max: u8::MAX as _,
27+
},
28+
},
29+
EnumInfo {
30+
ty_name: "i8",
31+
name: "i8_repr.rs",
32+
bit_info: BitInfo::Signed {
33+
signed_max: i8::MAX as _,
34+
signed_min: i8::MIN as _,
35+
prim_max: u8::MAX as _,
36+
},
37+
},
38+
#[cfg(feature = "enum_repr_16")]
39+
EnumInfo {
40+
ty_name: "u16",
41+
name: "u16_repr.rs",
42+
bit_info: BitInfo::Unsigned {
43+
prim_max: u16::MAX as _,
44+
},
45+
},
46+
#[cfg(feature = "enum_repr_16")]
47+
EnumInfo {
48+
ty_name: "i16",
49+
name: "i16_repr.rs",
50+
bit_info: BitInfo::Signed {
51+
signed_max: i16::MAX as _,
52+
signed_min: i16::MIN as _,
53+
prim_max: u16::MAX as _,
54+
},
55+
},
56+
];
57+
58+
fn generate_variants(
59+
mut generated_file: impl Write,
60+
repr_name: &str,
61+
bit_info: BitInfo,
62+
) -> Result<()> {
63+
write!(
64+
generated_file,
65+
"#[derive(Clone, Copy, PartialEq, Eq, Hash)]
66+
#[allow(dead_code)]
67+
pub(crate) enum {} {{",
68+
repr_name
69+
)?;
70+
71+
match bit_info {
72+
BitInfo::Unsigned { prim_max } => {
73+
for i in 0..prim_max {
74+
write!(generated_file, "V{},", i)?
75+
}
76+
}
77+
BitInfo::Signed {
78+
signed_max,
79+
signed_min,
80+
prim_max,
81+
} => {
82+
for i in 0..signed_max {
83+
write!(generated_file, "V{},", i)?;
84+
}
85+
86+
for (i, v) in (signed_max..prim_max).zip(signed_min..0) {
87+
write!(generated_file, "MV{}={},", i, v)?;
88+
}
89+
}
90+
}
91+
92+
write!(generated_file, "}}")?;
93+
Ok(())
94+
}
95+
96+
fn generate_impl(mut generated_file: impl Write, repr_name: &str, ty_name: &str) -> Result<()> {
97+
write!(
98+
generated_file,
99+
"impl {} {{
100+
pub(crate) const fn new(value: {}) -> Option<Self> {{
101+
unsafe {{ std::mem::transmute(value) }}
102+
}}
103+
}}",
104+
repr_name, ty_name
105+
)
106+
}
107+
108+
fn main() -> Result<()> {
109+
let out_dir = std::env::var("OUT_DIR").unwrap();
110+
111+
let mut open_options = std::fs::OpenOptions::new();
112+
open_options.create(true).write(true).truncate(true);
113+
114+
for file in FILES {
115+
let file_path = format!("{}/{}", out_dir, file.name);
116+
let mut generated_file = BufWriter::new(open_options.open(file_path)?);
117+
118+
let repr_name = format!("{}Repr", file.ty_name.to_uppercase());
119+
120+
generate_variants(&mut generated_file, &repr_name, file.bit_info)?;
121+
generate_impl(&mut generated_file, &repr_name, file.ty_name)?;
122+
123+
generated_file.flush()?;
124+
}
125+
126+
Ok(())
127+
}

src/enum_impl/mod.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#[cfg(feature = "enum_repr_16")]
2+
pub(crate) mod i16_repr {
3+
include!(concat!(env!("OUT_DIR"), "/i16_repr.rs"));
4+
}
5+
#[cfg(feature = "enum_repr_16")]
6+
pub(crate) mod u16_repr {
7+
include!(concat!(env!("OUT_DIR"), "/u16_repr.rs"));
8+
}
9+
pub(crate) mod i8_repr {
10+
include!(concat!(env!("OUT_DIR"), "/i8_repr.rs"));
11+
}
12+
pub(crate) mod u8_repr {
13+
include!(concat!(env!("OUT_DIR"), "/u8_repr.rs"));
14+
}
15+
16+
macro_rules! nonmax {
17+
( $nonmax: ident, $primitive: ident, $byte_repr: ident ) => {
18+
/// An integer that is known not to equal its maximum value.
19+
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
20+
#[repr(transparent)]
21+
pub struct $nonmax($byte_repr);
22+
23+
impl $nonmax {
24+
/// Creates a new non-max if the given value is not the maximum
25+
/// value.
26+
pub const fn new(value: $primitive) -> Option<Self> {
27+
match $byte_repr::new(value) {
28+
Some(byte) => Some(Self(byte)),
29+
None => None,
30+
}
31+
}
32+
33+
/// Creates a new non-max without checking the value.
34+
///
35+
/// # Safety
36+
///
37+
/// The value must not equal the maximum representable value for the
38+
/// primitive type.
39+
#[inline]
40+
pub const unsafe fn new_unchecked(value: $primitive) -> Self {
41+
match Self::new(value) {
42+
Some(this) => this,
43+
None => unsafe { std::hint::unreachable_unchecked() },
44+
}
45+
}
46+
47+
/// Returns the value as a primitive type.
48+
#[inline]
49+
pub const fn get(&self) -> $primitive {
50+
self.0 as $primitive
51+
}
52+
}
53+
};
54+
}
55+
56+
pub(crate) use nonmax;

src/lib.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ will only require minor version bumps, but will need significant justification.
5656
#![forbid(missing_docs)]
5757
#![cfg_attr(not(feature = "std"), no_std)]
5858

59+
#[macro_use]
60+
mod enum_impl;
61+
62+
#[cfg(feature = "enum_repr_16")]
63+
use enum_impl::i16_repr::I16Repr;
64+
#[cfg(feature = "enum_repr_16")]
65+
use enum_impl::u16_repr::U16Repr;
66+
use enum_impl::i8_repr::I8Repr;
67+
use enum_impl::u8_repr::U8Repr;
68+
5969
/// An error type returned when a checked integral type conversion fails (mimics [std::num::TryFromIntError])
6070
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6171
pub struct TryFromIntError(());
@@ -401,14 +411,27 @@ macro_rules! nonmax_impls {
401411
};
402412
}
403413

404-
nonmax_impls!(def, signed, NonMaxI8, NonZeroI8, i8);
414+
enum_impl::nonmax!(NonMaxI8, i8, I8Repr);
415+
enum_impl::nonmax!(NonMaxU8, u8, U8Repr);
416+
#[cfg(feature = "enum_repr_16")]
417+
enum_impl::nonmax!(NonMaxI16, i16, I16Repr);
418+
#[cfg(feature = "enum_repr_16")]
419+
enum_impl::nonmax!(NonMaxU16, u16, U16Repr);
420+
421+
nonmax_impls!(signed, NonMaxI8, NonZeroI8, i8);
422+
#[cfg(feature = "enum_repr_16")]
423+
nonmax_impls!(signed, NonMaxI16, NonZeroI16, i16);
424+
#[cfg(not(feature = "enum_repr_16"))]
405425
nonmax_impls!(def, signed, NonMaxI16, NonZeroI16, i16);
406426
nonmax_impls!(def, signed, NonMaxI32, NonZeroI32, i32);
407427
nonmax_impls!(def, signed, NonMaxI64, NonZeroI64, i64);
408428
nonmax_impls!(def, signed, NonMaxI128, NonZeroI128, i128);
409429
nonmax_impls!(def, signed, NonMaxIsize, NonZeroIsize, isize);
410430

411-
nonmax_impls!(def, unsigned, NonMaxU8, NonZeroU8, u8);
431+
nonmax_impls!(unsigned, NonMaxU8, NonZeroU8, u8);
432+
#[cfg(feature = "enum_repr_16")]
433+
nonmax_impls!(unsigned, NonMaxU16, NonZeroU16, u16);
434+
#[cfg(not(feature = "enum_repr_16"))]
412435
nonmax_impls!(def, unsigned, NonMaxU16, NonZeroU16, u16);
413436
nonmax_impls!(def, unsigned, NonMaxU32, NonZeroU32, u32);
414437
nonmax_impls!(def, unsigned, NonMaxU64, NonZeroU64, u64);

0 commit comments

Comments
 (0)