1#![no_std]
2#![doc = include_str!("../README.md")]
3#![allow(
4 clippy::partialeq_ne_impl,
5 clippy::non_canonical_partial_ord_impl,
6 reason = "bulk forwarding to integer methods is faster than handwriting the methods"
7)]
8
9mod conversions;
10
11#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
12#[repr(u8)]
13enum Zero {
14 _0 = 0,
15}
16
17const fn from_str_error(bad_val: &str) -> core::num::ParseIntError {
18 match i8::from_str_radix(bad_val, 10) {
19 Err(err) => err,
20 Ok(_) => unreachable!(),
21 }
22}
23
24const POSITIVE_OVERFLOW: core::num::ParseIntError = from_str_error("999");
25
26const NEGATIVE_OVERFLOW: core::num::ParseIntError = from_str_error("-999");
27
28#[cfg(feature = "bytemuck")]
29unsafe impl bytemuck::Zeroable for Zero {}
30
31#[cfg(feature = "bytemuck")]
32unsafe impl bytemuck::NoUninit for Zero {}
33
34const _: () = match (cfg!(target_endian = "big"), cfg!(target_endian = "little")) {
35 (true, false) | (false, true) => {}
36 (false, false) => panic!("unknown endianness"),
37 (true, true) => panic!("invalid endianness"),
38};
39
40macro_rules! declare_inner_struct {
41 ($name: ident @[$size: expr] { $($fields: tt)* }) => {
42 #[derive(Copy, Clone)]
43 #[repr(C, align($size))]
44 struct $name {
45 $($fields)*
46 }
47
48 #[cfg(feature = "bytemuck")]
52 unsafe impl bytemuck::NoUninit for $name {}
53 #[cfg(feature = "bytemuck")]
54 unsafe impl bytemuck::Zeroable for $name {}
55
56
57 const _: () = assert!(size_of::<$name>() == $size);
58 };
59}
60
61macro_rules! match_signedness {
62 (match I {
63 SIGNED => { $($tt:tt)* },
64 UNSIGNED => { $($_tt:tt)* } $(,)?
65 }) => {
66 $($tt)*
67 };
68
69 (match U {
70 SIGNED => { $($_tt:tt)* },
71 UNSIGNED => { $($tt:tt)* } $(,)?
72 }) => {
73 $($tt)*
74 };
75}
76
77macro_rules! forward_ref_op_assign {
78 (impl $imp:ident, $method:ident for $t:ty) => {
79 impl core::ops::$imp<&$t> for $t {
80 #[inline(always)]
81 fn $method(&mut self, other: &$t) {
82 core::ops::$imp::$method(self, *other);
83 }
84 }
85 };
86}
87
88macro_rules! forward_ref_binop {
89 (impl $imp:ident, $method:ident for $t:ty) => {
90 impl core::ops::$imp<$t> for &$t {
91 type Output = <$t as core::ops::$imp<$t>>::Output;
92
93 #[inline(always)]
94 fn $method(self, other: $t) -> Self::Output {
95 core::ops::$imp::$method(*self, other)
96 }
97 }
98
99 impl core::ops::$imp<&$t> for $t {
100 type Output = <$t as core::ops::$imp<$t>>::Output;
101
102 #[inline(always)]
103 fn $method(self, other: &$t) -> Self::Output {
104 core::ops::$imp::$method(self, *other)
105 }
106 }
107
108 impl core::ops::$imp<&$t> for &$t {
109 type Output = <$t as core::ops::$imp<$t>>::Output;
110
111 #[inline(always)]
112 fn $method(self, other: &$t) -> Self::Output {
113 core::ops::$imp::$method(*self, *other)
114 }
115 }
116 };
117}
118
119macro_rules! impl_wrapping_binop_inner {
120 ($(impl $imp:ident, $method:ident for ($ty:ty as $inner: ty) @ $fetch:ident)+) => {$(
121 impl core::ops::$imp for $ty {
122 type Output = $ty;
123
124 #[inline(always)]
125 fn $method(self, rhs: Self) -> Self::Output {
126 let lhs = self.$fetch();
127 let rhs = rhs.$fetch();
128 let result = pastey::paste!(<$inner>::[<wrapping_ $method>](lhs, rhs));
129 Self::new_truncated(result)
130 }
131 }
132
133 forward_ref_binop! { impl $imp, $method for $ty }
134
135 pastey::paste! {
136 impl core::ops::[<$imp Assign>] for $ty {
137 #[inline(always)]
138 fn [<$method _assign>](&mut self, rhs: Self) {
139 *self = <Self as core::ops::$imp>::$method(*self, rhs);
140 }
141 }
142
143 forward_ref_op_assign! { impl [<$imp Assign>], [<$method _assign>] for $ty }
144 }
145 )+}
146}
147
148macro_rules! impl_wrapping_bits_binop {
149 ($(impl $imp:ident, $method:ident for $t:ty as $inner: ty)+) => {$(
150 impl_wrapping_binop_inner! { impl $imp, $method for ($t as $inner) @ to_bits }
151 )+}
152}
153
154macro_rules! impl_wrapping_inner_binop {
155 ($(impl $imp:ident, $method:ident for $t:ty as $inner: ty)+) => {$(
156 impl_wrapping_binop_inner! { impl $imp, $method for ($t as $inner) @ get }
157 )+}
158}
159
160macro_rules! handle_argument {
161 ($arg_name: ident : Self) => {
162 $arg_name.get()
163 };
164 ($arg_name: ident : &Self) => {
165 &$arg_name.get()
166 };
167 ($arg_name: ident : &mut Self) => {
168 &mut $arg_name.get()
169 };
170 ($arg_name: ident : $arg_ty: ty) => {
171 $arg_name
172 };
173}
174
175macro_rules! defer_basic {
176 (
177 $(impl ($path: path) for $ty: ident as $inner: ty {
178 $(
179 $(#[$meta: meta])*
180 fn $method: ident ($(& $([$has_ref: tt])? $(mut $([$has_mut: tt])? )?)? self $(, $arg_name: ident : [$($arg_ty: tt)*])* $(,)?) -> $ret: ty;
181 )*
182 })*
183 ) => {$(
184 impl $path for $ty {
185 $(#[inline(always)]
186 $(#[$meta])*
187 fn $method($(& $($has_ref)? $(mut $($has_mut)? )?)? self $(, $arg_name : $($arg_ty)*)*) -> $ret {
188 <$inner as $path>::$method($(& $($has_ref)? $(mut $($has_mut)? )?)? self.get() $(, handle_argument!($arg_name: $($arg_ty)*))*)
189 })*
190 }
191 )*};
192}
193
194macro_rules! defer_impl {
195 (@($_sign_prefix: ident) $ty: ident as $inner: ty) => {
196 defer_basic! {
197 impl (core::fmt::Display) for $ty as $inner {
198 fn fmt(&self, f: [&mut core::fmt::Formatter<'_>]) -> core::fmt::Result;
199 }
200
201 impl (core::fmt::Debug) for $ty as $inner {
202 fn fmt(&self, f: [&mut core::fmt::Formatter<'_>]) -> core::fmt::Result;
203 }
204
205 impl (core::cmp::PartialEq) for $ty as $inner {
206 fn eq(&self, other: [&Self]) -> bool;
207
208 fn ne(&self, other: [&Self]) -> bool;
209 }
210
211 impl (core::cmp::Eq) for $ty as $inner {}
212
213
214 impl (core::cmp::PartialOrd) for $ty as $inner {
215 fn partial_cmp(&self, other: [&Self]) -> Option<core::cmp::Ordering>;
216
217
218 fn lt(&self, other: [&Self]) -> bool;
219 fn le(&self, other: [&Self]) -> bool;
220
221 fn gt(&self, other: [&Self]) -> bool;
222 fn ge(&self, other: [&Self]) -> bool;
223 }
224
225 impl (core::cmp::Ord) for $ty as $inner {
226 fn cmp(&self, other: [&Self]) -> core::cmp::Ordering;
227 }
228 }
229
230 impl core::hash::Hash for $ty {
231 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
232 <$inner as core::hash::Hash>::hash(
233 unsafe { &*(self as *const Self as *const $inner) },
235 state,
236 )
237 }
238
239 fn hash_slice<H: core::hash::Hasher>(data: &[Self], state: &mut H)
240 where
241 Self: Sized,
242 {
243 <$inner as core::hash::Hash>::hash_slice(
244 unsafe { &*(data as *const [Self] as *const [$inner]) },
247 state,
248 )
249 }
250 }
251
252 impl_wrapping_bits_binop! {
253 impl Add, add for $ty as $inner
254 impl Sub, sub for $ty as $inner
255 impl Mul, mul for $ty as $inner
256 }
257
258 impl_wrapping_inner_binop! {
259 impl Div, div for $ty as $inner
260 impl Rem, rem for $ty as $inner
261 }
262
263 impl $ty {
264 pub const fn from_str_radix(
265 str: &str,
266 radix: u32,
267 ) -> Result<Self, core::num::ParseIntError> {
268 match <$inner>::from_str_radix(str, radix) {
269 Err(err) => Err(err),
270 Ok(int) => match Self::new(int) {
271 Some(casted_int) => Ok(casted_int),
272 #[allow(unused_comparisons)]
274 None if int < 0 => Err(NEGATIVE_OVERFLOW),
275 None => Err(POSITIVE_OVERFLOW),
276 },
277 }
278 }
279 }
280
281 impl core::str::FromStr for $ty {
282 type Err = core::num::ParseIntError;
283
284 fn from_str(s: &str) -> Result<Self, Self::Err> {
285 Self::from_str_radix(s, 10)
286 }
287 }
288
289 #[cfg(feature = "serde")]
290 impl serde::Serialize for $ty {
291 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
292 where
293 S: serde::Serializer,
294 {
295 match serializer.is_human_readable() {
296 true => <$inner as serde::Serialize>::serialize(&self.get(), serializer),
297 false => <[u8; { (<$ty>::BITS / 8) as usize }] as serde::Serialize>::serialize(
298 &self.to_be_bytes(),
299 serializer,
300 ),
301 }
302 }
303 }
304
305 #[cfg(feature = "serde")]
306 impl<'de> serde::Deserialize<'de> for $ty {
307 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
308 where
309 D: serde::Deserializer<'de>,
310 {
311 match deserializer.is_human_readable() {
312 true => {
313 let int = <$inner as serde::Deserialize>::deserialize(deserializer)?;
314 match $ty::new(int) {
315 Some(int) => Ok(int),
316 None => Err(<D::Error as serde::de::Error>::custom(format_args!(
317 "invalid {int} as {}",
318 stringify!($ty)
319 ))),
320 }
321 }
322 false => {
323 <[u8; { (<$ty>::BITS / 8) as usize }] as serde::Deserialize>::deserialize(
324 deserializer,
325 )
326 .map(<$ty>::from_be_bytes)
327 }
328 }
329 }
330 }
331
332 #[cfg(feature = "num-traits")]
333 impl num_traits::One for $ty {
334 #[inline(always)]
335 fn one() -> Self {
336 <Self as num_traits::ConstOne>::ONE
337 }
338
339 #[inline]
340 fn is_one(&self) -> bool {
341 *self == <Self as num_traits::ConstOne>::ONE
342 }
343 }
344
345 #[cfg(feature = "num-traits")]
346 impl num_traits::ConstOne for $ty {
347 const ONE: Self = const_macro::$ty!(1);
348 }
349
350 #[cfg(feature = "num-traits")]
351 impl num_traits::Zero for $ty {
352 #[inline(always)]
353 fn zero() -> Self {
354 <Self as num_traits::ConstZero>::ZERO
355 }
356
357 #[inline(always)]
358 fn is_zero(&self) -> bool {
359 *self == <Self as num_traits::ConstZero>::ZERO
360 }
361 }
362
363 #[cfg(feature = "num-traits")]
364 impl num_traits::ConstZero for $ty {
365 const ZERO: Self = const_macro::$ty!(0);
366 }
367
368 #[cfg(feature = "num-traits")]
369 impl num_traits::Num for $ty {
370 type FromStrRadixErr = core::num::ParseIntError;
371
372 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
373 Self::from_str_radix(str, radix)
374 }
375 }
376 };
377}
378
379macro_rules! nbyte_int_inner {
380 (
381 $($backing_ty: ident @($signed_prefix: ident $size: expr) [$($byte_count: tt @ $bit_count: tt),+])*
382 ) => {
383 pastey::paste! {
384 pub mod types {
385 use super::*;
443
444 $(const _: () = {
445 let min = $size / 2;
446 let max = size_of::<$backing_ty>();
447 assert!($size == max, "invalid backing type size");
448 $(
449 assert!(
450 $bit_count == $byte_count * 8,
451 concat!(
452 "invalid nbyte bit count for ",
453 stringify!($byte_count),
454 " bytes",
455 )
456 );
457 assert!(min < $byte_count && $byte_count < max, "invalid nbyte int");
458 )*
459 let len = <[_]>::len(&[$($byte_count),*]);
460 assert!(len == max - min - 1, "not all byte integers implemented");
463 };
464
465 $(
466 declare_inner_struct! {
467 [<$signed_prefix $bit_count LittleEndian Inner>] @[$size] {
468 bytes: [u8; $byte_count],
469 zeros: [Zero; { $size - $byte_count }],
470 }
471 }
472
473 declare_inner_struct! {
474 [<$signed_prefix $bit_count BigEndian Inner>] @[$size] {
475 zeros: [Zero; { $size - $byte_count }],
476 bytes: [u8; $byte_count]
477 }
478 }
479
480
481 cfg_select! {
482 target_endian = "little" => {
483 type [<$signed_prefix $bit_count Inner>] = [<$signed_prefix $bit_count LittleEndian Inner>];
484 type [<Flipped $signed_prefix $bit_count Inner>] = [<$signed_prefix $bit_count BigEndian Inner>];
485 }
486 target_endian = "big" => {
487 type [<$signed_prefix $bit_count Inner>] = [<$signed_prefix $bit_count BigEndian Inner>];
488 type [<Flipped $signed_prefix $bit_count Inner>] = [<$signed_prefix $bit_count LittleEndian Inner>];
489 }
490 }
491
492
493 #[allow(non_camel_case_types)]
494 #[derive(Copy, Clone)]
495 #[repr(transparent)]
496 pub struct [<$signed_prefix:lower $bit_count>]([<$signed_prefix $bit_count Inner>]);
497
498 #[cfg(feature = "bytemuck")]
500 unsafe impl bytemuck::NoUninit for [<$signed_prefix:lower $bit_count>] {}
501 #[cfg(feature = "bytemuck")]
502 unsafe impl bytemuck::Zeroable for [<$signed_prefix:lower $bit_count>] {}
503
504 impl [<$signed_prefix:lower $bit_count>] {
505 const DATA_BITS_MASK: $backing_ty = (1 as $backing_ty)
506 .strict_shl($bit_count)
507 .strict_sub(1);
508
509 const MIN_INNER: $backing_ty = match_signedness! {
510 match $signed_prefix {
511 SIGNED => {
512 {
513 let abs_value = Self::DATA_BITS_MASK.isolate_highest_one();
514 abs_value.strict_neg()
517 }
518 },
519 UNSIGNED => { 0 },
520 }
521 };
522
523 const MAX_INNER: $backing_ty = match_signedness! {
524 match $signed_prefix {
525 SIGNED => { Self::DATA_BITS_MASK >> 1 },
526 UNSIGNED => { Self::DATA_BITS_MASK },
527 }
528 };
529
530
531 pub const BITS: u32 = $bit_count;
532
533 pub const MIN: Self = Self::new(Self::MIN_INNER).unwrap();
534 pub const MAX: Self = Self::new(Self::MAX_INNER).unwrap();
535
536 #[doc = concat!(
537 "Creates a [`", stringify!([<$signed_prefix:lower $bit_count>]), "`](struct@",
538 stringify!([<$signed_prefix:lower $bit_count>]), ") from a `",
539 stringify!($backing_ty), "`, returning [`None`] if the value does not fit in ",
540 stringify!($bit_count), " bits.\n\n",
541 "The valid range is [`MIN`](Self::MIN)`..=`[`MAX`](Self::MAX).\n\n",
542 "This is the checked counterpart of [`new_unchecked`](Self::new_unchecked) ",
543 "and [`new_truncated`](Self::new_truncated). It is `const`, so it can be used ",
544 "to build constants; the type's constant macro does exactly that and panics ",
545 "at compile time on failure.\n\n",
546 "# Examples\n\n",
547 "```\n",
548 "use nbyte_int::prelude::*;\n\n",
549 "assert_eq!(", stringify!([<$signed_prefix:lower $bit_count>]), "::new(0).map(|x| x.get()), Some(0));\n",
550 "assert_eq!(", stringify!([<$signed_prefix:lower $bit_count>]), "::new(",
551 stringify!([<$signed_prefix:lower $bit_count>]), "::MAX.get()).map(|x| x.get()), ",
552 "Some(", stringify!([<$signed_prefix:lower $bit_count>]), "::MAX.get()));\n",
553 "// one past the maximum does not fit\n",
554 "assert!(", stringify!([<$signed_prefix:lower $bit_count>]), "::MAX.get().checked_add(1)",
555 ".and_then(", stringify!([<$signed_prefix:lower $bit_count>]), "::new).is_none());\n",
556 "```"
557 )]
558 #[inline(always)]
559 pub const fn new(x: $backing_ty) -> Option<Self> {
560 match x {
561 Self::MIN_INNER..=Self::MAX_INNER => Some(unsafe { Self::new_unchecked(x) }),
562 _ => None
563 }
564 }
565
566 #[doc = concat!(
567 "Creates a [`", stringify!([<$signed_prefix:lower $bit_count>]), "`](struct@",
568 stringify!([<$signed_prefix:lower $bit_count>]), ") from a `",
569 stringify!($backing_ty), "` without checking that it fits in ",
570 stringify!($bit_count), " bits.\n\n",
571 "Prefer [`new`](Self::new) (checked) or [`new_truncated`](Self::new_truncated) ",
572 "(wrapping) unless the range check is provably redundant and measurably matters.\n\n",
573 "# Safety\n\n",
574 "`x` must be within [`MIN`](Self::MIN)`..=`[`MAX`](Self::MAX), i.e. the value ",
575 "[`new`](Self::new) would accept. Violating this is immediate UB",
576 )]
577 #[inline(always)]
578 pub const unsafe fn new_unchecked(x: $backing_ty) -> Self {
579 unsafe {
580 core::hint::assert_unchecked(Self::MIN_INNER <= x);
581 core::hint::assert_unchecked(x <= Self::MAX_INNER);
582 }
583
584 match_signedness! {
585 match $signed_prefix {
586 SIGNED => { Self::new_truncated(x) },
588 UNSIGNED => { unsafe { Self::from_bits(x) } },
590 }
591 }
592 }
593
594 #[doc = concat!(
595 "Creates a ",
596 $byte_count,
597 "-byte integer from its exact raw bit pattern, bypassing all masking."
598 )]
599 #[doc = concat!(
607 "Only the low ",
608 $byte_count,
609 " bytes of `bits` may be non-zero. The upper bytes must all be zero. ",
610 "Violating this is immediate undefined behavior (UB)."
611 )]
612 #[inline(always)]
613 pub const unsafe fn from_bits(bits: $backing_ty) -> Self {
614 unsafe {
616 core::hint::assert_unchecked(bits & const { !Self::DATA_BITS_MASK } == 0);
617 core::mem::transmute(bits)
618 }
619 }
620
621 #[doc = concat!(
622 "Creates a ",
623 $byte_count,
624 "-byte integer by truncating the upper bits of the provided value."
625 )]
626 #[inline(always)]
636 pub const fn new_truncated(bits: $backing_ty) -> Self {
637 unsafe { Self::from_bits(bits & Self::DATA_BITS_MASK) }
638 }
639
640 #[doc = concat!(
641 "Returns the raw bit pattern of the ",
642 $byte_count,
643 "-byte integer as its underlying backing type."
644 )]
645 #[inline(always)]
655 pub const fn to_bits(self) -> $backing_ty {
656 unsafe { core::mem::transmute(self) }
658 }
659
660 #[inline(always)]
661 const fn get_swapped_bytes_inner(self) -> [u8; $byte_count] {
662 let bits = self.to_bits();
663 let swapped = bits.swap_bytes();
664
665 let swapped: [<Flipped $signed_prefix $bit_count Inner>] = unsafe {
669 core::mem::transmute(swapped)
670 };
671
672 swapped.bytes
673 }
674
675 #[inline(always)]
676 pub const fn swap_bytes(self) -> Self {
677 Self::from_ne_bytes(self.get_swapped_bytes_inner())
680 }
681
682 #[inline(always)]
683 pub const fn from_le(x: Self) -> Self {
684 #[cfg(target_endian = "little")]
685 {
686 x
687 }
688
689 #[cfg(target_endian = "big")]
690 {
691 x.swap_bytes()
692 }
693 }
694
695 #[inline(always)]
696 pub const fn from_be(x: Self) -> Self {
697 #[cfg(target_endian = "big")]
698 {
699 x
700 }
701
702 #[cfg(target_endian = "little")]
703 {
704 x.swap_bytes()
705 }
706 }
707
708 #[inline(always)]
709 pub const fn to_le(self) -> Self {
710 Self::from_le(self)
711 }
712
713 #[inline(always)]
714 pub const fn to_be(self) -> Self {
715 Self::from_be(self)
716 }
717
718 #[inline(always)]
719 pub const fn from_ne_bytes(bytes: [u8; $byte_count]) -> Self {
720 Self([<$signed_prefix $bit_count Inner>]{
721 zeros: [Zero::_0; { $size - $byte_count }],
722 bytes
723 })
724 }
725
726 #[inline(always)]
727 pub const fn from_le_bytes(bytes: [u8; $byte_count]) -> Self {
728 Self::from_le(Self::from_ne_bytes(bytes))
729 }
730
731 #[inline(always)]
732 pub const fn from_be_bytes(bytes: [u8; $byte_count]) -> Self {
733 Self::from_be(Self::from_ne_bytes(bytes))
734 }
735
736 #[inline(always)]
737 pub const fn to_ne_bytes(self) -> [u8; $byte_count] {
738 self.0.bytes
739 }
740
741 #[inline(always)]
742 pub const fn to_le_bytes(self) -> [u8; $byte_count] {
743 #[cfg(target_endian = "little")]
744 {
745 self.0.bytes
746 }
747
748 #[cfg(target_endian = "big")]
749 {
750 self.get_swapped_bytes_inner()
751 }
752 }
753
754 #[inline(always)]
755 pub const fn to_be_bytes(self) -> [u8; $byte_count] {
756 #[cfg(target_endian = "big")]
757 {
758 self.0.bytes
759 }
760
761 #[cfg(target_endian = "little")]
762 {
763 self.get_swapped_bytes_inner()
764 }
765 }
766
767 #[doc = concat!(
768 "Returns the logical value of the ",
769 $byte_count,
770 "-byte integer as its underlying `",
771 stringify!($backing_ty),
772 "` backing type."
773 )]
774 #[inline(always)]
783 pub const fn get(self) -> $backing_ty {
784 match_signedness! {
785 match $signed_prefix {
786 SIGNED => {
787 {
788 const OFFSET: u32 = $backing_ty::BITS
789 .strict_sub(<[<$signed_prefix:lower $bit_count>]>::BITS);
790
791 let bits = self.to_bits();
792 unsafe { bits.unchecked_shl(OFFSET).unchecked_shr(OFFSET) }
796 }
797 },
798 UNSIGNED => { self.to_bits() },
800 }
801 }
802 }
803 }
804
805 defer_impl!(@($signed_prefix) [<$signed_prefix:lower $bit_count>] as $backing_ty);
806 )*
807 )*
808 }
809
810
811 pub mod literal {
812 #[cfg(doc)]
817 use crate::types::*;
818
819 $($(
820 #[macro_export]
821 #[doc = concat!(
822 "Creates a [`", stringify!([<$signed_prefix:lower $bit_count>]), "`](struct@", stringify!([<$signed_prefix:lower $bit_count>]), ") from an integer literal, ",
823 "checked at compile time.\n\n",
824 "Fails to compile if the literal is outside [`MIN`](", stringify!([<$signed_prefix:lower $bit_count>]), "::MIN)`..=`",
825 "[`MAX`](", stringify!([<$signed_prefix:lower $bit_count>]), "::MAX). Only literals are accepted; for other constant ",
826 "expressions use `const { ", stringify!([<$signed_prefix:lower $bit_count>]), "::new(expr).unwrap() }`.\n\n",
827 "# Examples\n\n",
828 "```\n",
829 "use nbyte_int::const_macro::", stringify!([<$signed_prefix:lower $bit_count>]), ";\n\n",
830 "const X: nbyte_int::types::", stringify!([<$signed_prefix:lower $bit_count>]), " = ", stringify!([<$signed_prefix:lower $bit_count>]), "!(1);\n",
831 "assert_eq!(X.get(), 1);\n",
832 "```\n\n",
833 "An out-of-range literal is a compile error.",
834 )]
835 #[doc(hidden)]
836 macro_rules! [<__ $signed_prefix:lower $bit_count __>] {
837 ($__inner_expr__: literal) => {
838 const {
839 match $crate::types::[<$signed_prefix:lower $bit_count>]::new($__inner_expr__) {
840 Some(x) => x,
841 None => panic!(concat!(
842 "invalid ",
843 stringify!([<$signed_prefix:lower $bit_count>]),
844 " literal `",
845 $__inner_expr__,
846 "`"
847 ))
848 }
849 }
850 }
851 }
852
853 #[doc(inline)]
854 pub use [<__ $signed_prefix:lower $bit_count __>] as [<$signed_prefix:lower $bit_count>];
855 )*)*
856 }
857 }
858 };
859}
860
861macro_rules! nbyte_int {
862 (
863 $($backing: tt @($size: expr) [$($byte_count: tt @ $bit_count: tt),+ $(,)?])*
864 ) => {
865 pastey::paste! {
866 nbyte_int_inner! {
867 $(
868 [<i $backing>] @(I $size) [$($byte_count @ $bit_count),+]
869 [<u $backing>] @(U $size) [$($byte_count @ $bit_count),+]
870 )*
871 }
872 }
873 };
874}
875
876nbyte_int! {
877 32 @(4) [3 @ 24]
879 64 @(8) [5 @ 40, 6 @ 48, 7 @ 56]
880 128 @(16) [9 @ 72, 10 @ 80, 11 @ 88, 12 @ 96, 13 @ 104, 14 @ 112, 15 @ 120]
881}
882
883pub mod prelude {
884 pub use crate::literal::*;
890 pub use crate::types::*;
891}