oxedyne/fe2o3/fe2o3_core/src/macros/fallible.rs
7.0 KiB, 55 runs
created by r1870400018:98, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | #[macro_export] |
| 2 | /// Shortcut for attempt to convert type. |
| 3 | /// |
| 4 | ///``` |
| 5 | /// use oxedyne_fe2o3_core::prelude::*; |
| 6 | /// |
| 7 | /// fn main() -> Outcome<()> { |
| 8 | /// let n = 42u32; |
| 9 | /// let n1 = try_into!(usize, n); |
| 10 | /// let n2 = res!(TryInto::<usize>::try_into(n)); |
| 11 | /// assert_eq!(n1, n2); |
| 12 | /// Ok(()) |
| 13 | /// } |
| 14 | /// |
| 15 | ///``` |
| 16 | macro_rules! try_into { |
| 17 | ($typ:tt, $expr:expr) => { |
| 18 | match TryInto::<$typ>::try_into($expr) { |
| 19 | Ok(v) => v, |
| 20 | Err(e) => return Err(err!(e, |
| 21 | "Could not convert {:?} into {:?}.", $expr, std::any::type_name::<$typ>(); |
| 22 | Bug, Conversion)), |
| 23 | } |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | #[macro_export] |
| 28 | /// Shortcut for attempt to add integers that can overflow. |
| 29 | /// |
| 30 | ///``` |
| 31 | /// use oxedyne_fe2o3_core::prelude::*; |
| 32 | /// |
| 33 | /// fn main() -> Outcome<()> { |
| 34 | /// //let sum = try_add!(255u8, 1); // Will return an overflow error |
| 35 | /// let sum = try_add!(254u8, 1); // No error, returns value |
| 36 | /// Ok(()) |
| 37 | /// } |
| 38 | /// |
| 39 | ///``` |
| 40 | macro_rules! try_add { |
| 41 | ($n1:expr, $n2:expr $(,)?) => { |
| 42 | match $n1.checked_add($n2) { |
| 43 | Some(result) => result, |
| 44 | None => return Err(err!( |
| 45 | "Attempt to add {} and {} (type {}) resulted in integer overflow.", |
| 46 | $n1, $n2, fmt_typ!($n1); |
| 47 | Integer, Overflow)), |
| 48 | } |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | #[macro_export] |
| 53 | /// Shortcut for attempt to subtract integers that can underflow. |
| 54 | /// |
| 55 | ///``` |
| 56 | /// use oxedyne_fe2o3_core::prelude::*; |
| 57 | /// |
| 58 | /// fn main() -> Outcome<()> { |
| 59 | /// //let sum = try_sub!(1u8, 2); // Will return an overflow error |
| 60 | /// let sum = try_sub!(2u8, 1); // No error, returns value |
| 61 | /// Ok(()) |
| 62 | /// } |
| 63 | /// |
| 64 | ///``` |
| 65 | macro_rules! try_sub { |
| 66 | ($n1:expr, $n2:expr $(,)?) => { |
| 67 | match $n1.checked_sub($n2) { |
| 68 | Some(result) => result, |
| 69 | None => return Err(err!( |
| 70 | "Attempt to subtract {} from {} (type {}) resulted in integer underflow.", |
| 71 | $n2, $n1, fmt_typ!($n1); |
| 72 | Integer, Underflow)), |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | #[macro_export] |
| 78 | /// Shortcut for attempt to multiply integers that can overflow. |
| 79 | /// |
| 80 | ///``` |
| 81 | /// use oxedyne_fe2o3_core::prelude::*; |
| 82 | /// |
| 83 | /// fn main() -> Outcome<()> { |
| 84 | /// //let prod = try_mul!(17u8, 17); // Will return an overflow error |
| 85 | /// let prod = try_mul!(15u8, 15); // No error, returns value |
| 86 | /// Ok(()) |
| 87 | /// } |
| 88 | /// |
| 89 | ///``` |
| 90 | macro_rules! try_mul { |
| 91 | ($n1:expr, $n2:expr $(,)?) => { |
| 92 | match $n1.checked_mul($n2) { |
| 93 | Some(result) => result, |
| 94 | None => return Err(err!( |
| 95 | "Attempt to multiply {} and {} (type {}) resulted in integer overflow.", |
| 96 | $n1, $n2, fmt_typ!($n1); |
| 97 | Integer, Overflow)), |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | #[macro_export] |
| 103 | /// Shortcut for attempt to divide integers, checking for division by zero. |
| 104 | /// |
| 105 | ///``` |
| 106 | /// use oxedyne_fe2o3_core::prelude::*; |
| 107 | /// |
| 108 | /// fn main() -> Outcome<()> { |
| 109 | /// //let div = try_div!(17u8, 0); // Will return an error |
| 110 | /// let div = try_div!(15u8, 4); // No error, returns value |
| 111 | /// Ok(()) |
| 112 | /// } |
| 113 | /// |
| 114 | ///``` |
| 115 | macro_rules! try_div { |
| 116 | ($n1:expr, $n2:expr $(,)?) => { |
| 117 | match $n1.checked_div($n2) { |
| 118 | Some(result) => result, |
| 119 | None => return Err(err!( |
| 120 | "Attempt to divide {} by {} (type {}).", |
| 121 | $n1, $n2, fmt_typ!($n1); |
| 122 | Integer, ZeroDenominator)), |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | #[macro_export] |
| 128 | /// Shortcut for attempt to find the remainder after division, checking for division by zero. |
| 129 | /// |
| 130 | ///``` |
| 131 | /// use oxedyne_fe2o3_core::prelude::*; |
| 132 | /// |
| 133 | /// fn main() -> Outcome<()> { |
| 134 | /// //let rem = try_rem!(17u8, 0); // Will return an error |
| 135 | /// let rem = try_rem!(15u8, 4); // No error, returns value |
| 136 | /// Ok(()) |
| 137 | /// } |
| 138 | /// |
| 139 | ///``` |
| 140 | macro_rules! try_rem { |
| 141 | ($n1:expr, $n2:expr $(,)?) => { |
| 142 | match $n1.checked_rem($n2) { |
| 143 | Some(result) => result, |
| 144 | None => return Err(err!( |
| 145 | "Attempt to find the remainder when {} is divided by {} (type {}).", |
| 146 | $n1, $n2, fmt_typ!($n1); |
| 147 | Integer, ZeroDenominator)), |
| 148 | } |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | #[macro_export] |
| 153 | /// Shortcut for check on whether the given expression fits within range. Intended for numbers but |
| 154 | /// works for anything that is `std::cmp::PartialOrd`. The user is responsible for ensuring valid |
| 155 | /// specification or inference of types. |
| 156 | /// |
| 157 | ///``` |
| 158 | /// use oxedyne_fe2o3_core::prelude::*; |
| 159 | /// |
| 160 | /// fn main() -> Outcome<()> { |
| 161 | /// //let n = try_range!(3u8, 5u8, 17u8); // Will return an error |
| 162 | /// let n = try_range!(6u8, 5u8, 17u8); // No error, returns 6u8 |
| 163 | /// Ok(()) |
| 164 | /// } |
| 165 | /// |
| 166 | ///``` |
| 167 | macro_rules! try_range { |
| 168 | ($n:expr, $min:expr, $max:expr $(,)?) => { |
| 169 | match (&$n, &$min, &$max) { |
| 170 | (n, min, max) if std::cmp::PartialOrd::lt(n, min) || std::cmp::PartialOrd::gt(n, max) => { |
| 171 | return Err(err!( |
| 172 | "{} is outside range [{}, {}].", $n, $min, $max; |
| 173 | Numeric, Range)); |
| 174 | } |
| 175 | _ => $n, |
| 176 | } |
| 177 | }; |
| 178 | } |
| 179 | |
| 180 | /// Implement some basic traits for native integers. |
| 181 | #[macro_export] |
| 182 | macro_rules! impls_for_native_integer { |
| 183 | ($t:ty, $n:literal) => { |
| 184 | |
| 185 | impl oxedyne_fe2o3_core::byte::FromBytes for $t { |
| 186 | fn from_bytes(buf: &[u8]) -> Outcome<(Self, usize)> { |
| 187 | const BYTE_LEN: usize = std::mem::size_of::<$t>(); |
| 188 | if buf.len() < BYTE_LEN { |
| 189 | return Err(err!( |
| 190 | "Not enough bytes to decode, require at least {} \ |
| 191 | for a {}, slice is of length {}.", |
| 192 | BYTE_LEN, std::any::type_name::<Self>(), buf.len(); |
| 193 | Bytes, Invalid, Input, Decode, Missing)); |
| 194 | } |
| 195 | let n = <$t>::from_be_bytes(res!( |
| 196 | <[u8; BYTE_LEN]>::try_from(&buf[0..BYTE_LEN]), |
| 197 | Decode, Bytes, Integer, |
| 198 | )); |
| 199 | Ok((n, BYTE_LEN)) |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | impl oxedyne_fe2o3_core::byte::FromByteArray for $t { |
| 204 | fn from_byte_array<const L: usize>(buf: [u8; L]) -> Outcome<Self> { |
| 205 | const BYTE_LEN: usize = std::mem::size_of::<$t>(); |
| 206 | if L < BYTE_LEN { |
| 207 | return Err(err!( |
| 208 | "Not enough bytes to decode, require at least {} \ |
| 209 | for a {}, array is of length {}.", |
| 210 | BYTE_LEN, std::any::type_name::<Self>(), L; |
| 211 | Bytes, Invalid, Input, Decode, Missing)); |
| 212 | } |
| 213 | Ok(<$t>::from_be_bytes(res!( |
| 214 | <[u8; BYTE_LEN]>::try_from(&buf[0..BYTE_LEN]), |
| 215 | Decode, Bytes, Integer, |
| 216 | ))) |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | impl oxedyne_fe2o3_core::byte::ToBytes for $t { |
| 221 | fn to_bytes(&self, mut buf: Vec<u8>) -> Outcome<Vec<u8>> { |
| 222 | buf.extend_from_slice(&self.to_be_bytes()); |
| 223 | Ok(buf) |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | impl oxedyne_fe2o3_core::byte::ToByteArray<$n> for $t { |
| 228 | fn to_byte_array(&self) -> [u8; $n] { |
| 229 | self.to_be_bytes() |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | impl oxedyne_fe2o3_core::string::ToHexString for $t {} |
| 234 | } |
| 235 | } |