at master 13 kB view raw
1/// Print to stdout 2#[macro_export] 3macro_rules! print { 4 ($($arg:tt)*) => ({ 5 use core::fmt::Write; 6 let _ = write!($crate::platform::FileWriter::new(1), $($arg)*); 7 }); 8} 9 10/// Print with new line to stdout 11#[macro_export] 12macro_rules! println { 13 () => (print!("\n")); 14 ($fmt:expr) => (print!(concat!($fmt, "\n"))); 15 ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); 16} 17 18/// Print to stderr 19#[macro_export] 20macro_rules! eprint { 21 ($($arg:tt)*) => ({ 22 use core::fmt::Write; 23 let _ = write!($crate::platform::FileWriter::new(2), $($arg)*); 24 }); 25} 26 27/// Print with new line to stderr 28#[macro_export] 29macro_rules! eprintln { 30 () => (eprint!("\n")); 31 ($fmt:expr) => (eprint!(concat!($fmt, "\n"))); 32 ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*)); 33} 34 35/// Lifted from libstd 36#[macro_export] 37macro_rules! dbg { 38 // NOTE: We cannot use `concat!` to make a static string as a format argument 39 // of `eprintln!` because `file!` could contain a `{` or 40 // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!` 41 // will be malformed. 42 () => { 43 eprintln!("[{}:{}:{}]", file!(), line!(), column!()); 44 }; 45 ($val:expr) => { 46 // Use of `match` here is intentional because it affects the lifetimes 47 // of temporaries - https://stackoverflow.com/a/48732525/1063961 48 match $val { 49 tmp => { 50 eprintln!( 51 "[{}:{}:{}] {} = {:#?}", 52 file!(), 53 line!(), 54 column!(), 55 stringify!($val), 56 &tmp 57 ); 58 tmp 59 } 60 } 61 }; 62 ($($val:expr),+ $(,)?) => { 63 ($(dbg!($val)),+,) 64 }; 65} 66 67#[macro_export] 68#[cfg(not(feature = "trace"))] 69macro_rules! trace { 70 ($($arg:tt)*) => {}; 71} 72 73#[macro_export] 74#[cfg(feature = "trace")] 75macro_rules! trace { 76 ($($arg:tt)*) => ({ 77 eprintln!($($arg)*); 78 }); 79} 80 81#[macro_export] 82#[cfg(not(feature = "trace"))] 83macro_rules! trace_expr { 84 ($expr:expr, $($arg:tt)*) => { 85 $expr 86 }; 87} 88 89#[macro_export] 90#[cfg(feature = "trace")] 91macro_rules! trace_expr { 92 ($expr:expr, $($arg:tt)*) => ({ 93 use $crate::header::errno::STR_ERROR; 94 use $crate::platform; 95 96 trace!("{}", format_args!($($arg)*)); 97 98 let trace_old_errno = platform::ERRNO.get(); 99 platform::ERRNO.set(0); 100 101 let ret = $expr; 102 103 let trace_errno = platform::ERRNO.get() as isize; 104 if trace_errno == 0 { 105 platform::ERRNO.set(trace_old_errno); 106 } 107 108 let trace_strerror = if trace_errno >= 0 && trace_errno < STR_ERROR.len() as isize { 109 STR_ERROR[trace_errno as usize] 110 } else { 111 "Unknown error" 112 }; 113 114 trace!("{} = {} ({}, {})", format_args!($($arg)*), ret, trace_errno, trace_strerror); 115 116 ret 117 }); 118} 119 120#[macro_export] 121macro_rules! strto_impl { 122 ( 123 $rettype:ty, $signed:expr, $maxval:expr, $minval:expr, $s:ident, $endptr:ident, $base:ident 124 ) => {{ 125 // ensure these are constants 126 const CHECK_SIGN: bool = $signed; 127 const MAX_VAL: $rettype = $maxval; 128 const MIN_VAL: $rettype = $minval; 129 130 let set_endptr = |idx: isize| { 131 if !$endptr.is_null() { 132 // This is stupid, but apparently strto* functions want 133 // const input but mut output, yet the man page says 134 // "stores the address of the first invalid character in *endptr" 135 // so obviously it doesn't want us to clone it. 136 *$endptr = $s.offset(idx) as *mut _; 137 } 138 }; 139 140 let invalid_input = || { 141 platform::ERRNO.set(EINVAL); 142 set_endptr(0); 143 }; 144 145 // only valid bases are 2 through 36 146 if $base != 0 && ($base < 2 || $base > 36) { 147 invalid_input(); 148 return 0; 149 } 150 151 let mut idx = 0; 152 153 // skip any whitespace at the beginning of the string 154 while ctype::isspace(*$s.offset(idx) as c_int) != 0 { 155 idx += 1; 156 } 157 158 // check for +/- 159 let positive = match is_positive(*$s.offset(idx)) { 160 Some((pos, i)) => { 161 idx += i; 162 pos 163 } 164 None => { 165 invalid_input(); 166 return 0; 167 } 168 }; 169 170 // convert the string to a number 171 let num_str = $s.offset(idx); 172 let res = match $base { 173 0 => detect_base(num_str).and_then(|($base, i)| { 174 idx += i; 175 convert_integer(num_str.offset(i), $base) 176 }), 177 8 => convert_octal(num_str), 178 16 => convert_hex(num_str), 179 _ => convert_integer(num_str, $base), 180 }; 181 182 // check for error parsing octal/hex prefix 183 // also check to ensure a number was indeed parsed 184 let (num, i, overflow) = match res { 185 Some(res) => res, 186 None => { 187 invalid_input(); 188 return 0; 189 } 190 }; 191 idx += i; 192 193 let overflow = if CHECK_SIGN { 194 overflow || (num as c_long).is_negative() 195 } else { 196 overflow 197 }; 198 // account for the sign 199 let num = num as $rettype; 200 let num = if overflow { 201 platform::ERRNO.set(ERANGE); 202 if CHECK_SIGN { 203 if positive { MAX_VAL } else { MIN_VAL } 204 } else { 205 MAX_VAL 206 } 207 } else { 208 if positive { 209 num 210 } else { 211 // not using -num to keep the compiler happy 212 num.overflowing_neg().0 213 } 214 }; 215 216 set_endptr(idx); 217 218 num 219 }}; 220} 221 222#[macro_export] 223macro_rules! strto_float_impl { 224 ($type:ident, $s:expr, $endptr:expr) => {{ 225 let mut s = $s; 226 let endptr = $endptr; 227 228 while ctype::isspace(*s as c_int) != 0 { 229 s = s.offset(1); 230 } 231 232 let mut result: $type = 0.0; 233 let mut exponent: Option<$type> = None; 234 let mut radix = 10; 235 236 let result_sign = match *s as u8 { 237 b'-' => { 238 s = s.offset(1); 239 -1.0 240 } 241 b'+' => { 242 s = s.offset(1); 243 1.0 244 } 245 _ => 1.0, 246 }; 247 248 let rust_s = CStr::from_ptr(s).to_string_lossy(); 249 250 // detect NaN, Inf 251 if rust_s.to_lowercase().starts_with("inf") { 252 result = $type::INFINITY; 253 s = s.offset(3); 254 } else if rust_s.to_lowercase().starts_with("nan") { 255 // we cannot signal negative NaN in LLVM backed languages 256 // https://github.com/rust-lang/rust/issues/73328 , https://github.com/rust-lang/rust/issues/81261 257 result = $type::NAN; 258 s = s.offset(3); 259 } else { 260 if *s as u8 == b'0' && *s.offset(1) as u8 == b'x' { 261 s = s.offset(2); 262 radix = 16; 263 } 264 265 while let Some(digit) = (*s as u8 as char).to_digit(radix) { 266 result *= radix as $type; 267 result += digit as $type; 268 s = s.offset(1); 269 } 270 271 if *s as u8 == b'.' { 272 s = s.offset(1); 273 274 let mut i = 1.0; 275 while let Some(digit) = (*s as u8 as char).to_digit(radix) { 276 i *= radix as $type; 277 result += digit as $type / i; 278 s = s.offset(1); 279 } 280 } 281 282 let s_before_exponent = s; 283 284 exponent = match (*s as u8, radix) { 285 (b'e' | b'E', 10) | (b'p' | b'P', 16) => { 286 s = s.offset(1); 287 288 let is_exponent_positive = match *s as u8 { 289 b'-' => { 290 s = s.offset(1); 291 false 292 } 293 b'+' => { 294 s = s.offset(1); 295 true 296 } 297 _ => true, 298 }; 299 300 // Exponent digits are always in base 10. 301 if (*s as u8 as char).is_digit(10) { 302 let mut exponent_value = 0; 303 304 while let Some(digit) = (*s as u8 as char).to_digit(10) { 305 exponent_value *= 10; 306 exponent_value += digit; 307 s = s.offset(1); 308 } 309 310 let exponent_base = match radix { 311 10 => 10u128, 312 16 => 2u128, 313 _ => unreachable!(), 314 }; 315 316 if is_exponent_positive { 317 Some(exponent_base.pow(exponent_value) as $type) 318 } else { 319 Some(1.0 / (exponent_base.pow(exponent_value) as $type)) 320 } 321 } else { 322 // Exponent had no valid digits after 'e'/'p' and '+'/'-', rollback 323 s = s_before_exponent; 324 None 325 } 326 } 327 _ => None, 328 }; 329 } 330 331 if !endptr.is_null() { 332 // This is stupid, but apparently strto* functions want 333 // const input but mut output, yet the man page says 334 // "stores the address of the first invalid character in *endptr" 335 // so obviously it doesn't want us to clone it. 336 *endptr = s as *mut _; 337 } 338 339 if let Some(exponent) = exponent { 340 result_sign * result * exponent 341 } else { 342 result_sign * result 343 } 344 }}; 345} 346 347/// Project an `Out<struct X { field: Type }>` to `struct X { field: Out<Type> }`. 348/// 349/// It is allowed to include only a subset of the struct's fields. The struct must implement 350/// `OutProject`. 351#[macro_export] 352macro_rules! out_project { 353 { 354 let $struct:ty { $($field:ident : $fieldty:ty),*$(,)? } = $src:ident; 355 } => { 356 // Verify $src actually has type Out<$struct>. Also verify it implements `OutProject`. This 357 // excludes 358 // 359 // - the case where $src is Out<&Struct>, where it would be very UB to just construct a 360 // writable reference to $src.$field, or a smart pointer 361 // - the case where there are unaligned fields where it would be UB to call ptr::write to 362 // them (requiring packed structs) 363 { 364 fn ensure_type<U: $crate::out::OutProject>(_t: &$crate::out::Out<U>) {} 365 ensure_type::<$struct>(&$src); 366 } 367 // Verify there are no duplicate struct fields. This is not strictly necessary as Out lacks 368 // the noalias requirement, but forbidding the same field to occur multiple times would 369 // allow both cases. The compiler will reject any struct that reuses the same identifier. 370 const _: () = { 371 $( 372 if ::core::mem::offset_of!($struct, $field) % ::core::mem::align_of::<$fieldty>() != 0 { 373 panic!(concat!("unaligned field ", stringify!($field), " of struct ", stringify!($struct), ".")); 374 } 375 )* 376 struct S { 377 $( 378 $field: $fieldty 379 ),* 380 } 381 }; 382 383 // Finally, create an Out<$fieldty> for each field. 384 $( 385 // getting the pointer to $field is safe 386 let $field = unsafe { &raw mut (*$crate::out::Out::<_>::as_mut_ptr(&mut $src)).$field }; 387 )* 388 $( 389 let mut $field: $crate::out::Out<$fieldty> = unsafe { 390 // SAFETY: the only guarantee is that the pointer is valid and writable for the 391 // duration of 'b where $src: Out<'b, T>. But if so, and T is a struct, that 392 // must also be true for all the struct fields. 393 $crate::out::Out::with_lifetime_of( 394 $crate::out::Out::nonnull($field), 395 &$src, 396 ) 397 }; 398 )* 399 } 400} 401#[macro_export] 402macro_rules! OutProject { 403 derive() { $(#[$($attrs:meta),*])* $v:vis struct $name:ident { 404 $( 405 $(#[$($fa:meta),*])* $fv:vis $field:ident : $type:ty 406 ),*$(,)? 407 } } => { 408 // SAFETY: As simple as it is, OutProject is valid for any struct, and the pattern we have 409 // matched above ensures $name is one. 410 unsafe impl $crate::out::OutProject for $name {} 411 } 412}