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
/* * indent-stack * * Copyright (C) 2019 chankyin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /// This macro generates a struct that implements `Modular`. /// /// See [`ExampleModular101`](struct.ExampleModular101.html) for an example of what is generated. /// /// # Parameters /// - `$name` is the name of the struct to be generated. /// - `$int` is the type of integer to work with. It must be one of `u8`, `u16`, `u32`, `u64` or /// `u128`. /// - `$sint` is the type of integer to work with. It must be the signed version of `$int`, i.e. /// `i8`, `i16`, `i32`, `i64` or `i128`. /// - `$mod` is the modulus of this type of modular value. It must be a const value. It must /// satisfy `$mod * $mod < $int::max_value()` and `$mod * 2 < $sint::max_value()`. /// - `$label` is a dummy label name for static assertions. This is unused on nightly builds with /// the `underscore_const_names` feature. /// /// # Example /// ```ignore /// def_modular!(ExampleModular101 : u16 | i16, 101 ; some_random_label /// #[doc = "your own documentation here"]); /// ``` #[macro_export] macro_rules! def_modular { ($name:ident : $int:ty | $sint:ty, $mod:expr ; $label:ident $(#[$docs:meta])*) => { #[allow(unused)] mod $label { use core::fmt::Debug; use core::ops::{Add, Mul, Rem, Sub}; static_assertions::assert_impl!(impl_modular; $int, Copy, Debug, Default, Add, Sub, Mul, Rem); static_assertions::const_assert!(overflow_check; { ($mod as u128) <= (<$int>::max_value() as u128) && ($mod as u128) + ($mod as u128) <= (<$sint>::max_value() as u128) && ($mod as u128) <= (u64::max_value() as u128) && // self < u64::max is required for u128 (and automatically true for all other types) ($mod as u128) * ($mod as u128) < (<$int>::max_value() as u128) // squared must not overflow since it is less than u64::max }); } $(#[$docs])* #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct $name($int); impl $name { /// Instantiated from the signed type, useful for literal instantiation. /// /// Use the `From` conversions instead if the input is not a literal. const fn new(mut int: $sint) -> Self { int %= $mod; // now int is in (-$mod, $mod) int += $mod; // now int is in (0, $mod * 2), int %= $mod; // now int is in [0, $mod) Self(int as $int) } } impl $crate::Modular<$int> for $name { const MOD: $int = $mod; fn remainder(&self) -> $int { self.0 } } /// Converts a number of the base type into this modular type. /// /// Use the `new` method instead for literal inputs, because the compiler canot determine /// if the signed `From` or the unsigned `From` is intended. impl From<$int> for $name { fn from(int: $int) -> Self { Self(int % $mod) } } /// Converts a number of the signed type into this modular type. /// /// Use the `new` method instead for literal inputs, because the compiler canot determine /// if the signed `From` or the unsigned `From` is intended. impl From<$sint> for $name { fn from(int: $sint) -> Self { Self::new(int) } } impl ::core::ops::Add for $name { type Output = Self; fn add(self, rhs: Self) -> Self { Self((self.0 + rhs.0) % $mod) } } impl ::core::ops::Sub for $name { type Output = Self; fn sub(self, rhs: Self) -> Self { // add $mod to prevent negative integer overflow Self(((self.0 + $mod) - rhs.0) % $mod) } } impl ::core::ops::Mul for $name { type Output = Self; fn mul(self, rhs: Self) -> Self { Self((self.0 * rhs.0) % $mod) } } }; }