#[cfg(feature = "std")]
use std::{f32, f64};
#[cfg(feature = "std")]
pub(crate) const F32_NAN: f32 = f32::NAN;
#[cfg(not(feature = "std"))]
pub(crate) const F32_NAN: f32 = 0.0_f32 / 0.0_f32;
#[cfg(feature = "std")]
pub(crate) const F32_INFINITY: f32 = f32::INFINITY;
#[cfg(not(feature = "std"))]
pub(crate) const F32_INFINITY: f32 = 1.0_f32 / 0.0_f32;
#[cfg(feature = "std")]
pub(crate) const F64_NAN: f64 = f64::NAN;
#[cfg(not(feature = "std"))]
pub(crate) const F64_NAN: f64 = 0.0_f64 / 0.0_f64;
#[cfg(feature = "std")]
pub(crate) const F64_INFINITY: f64 = f64::INFINITY;
#[cfg(not(feature = "std"))]
pub(crate) const F64_INFINITY: f64 = 1.0_f64 / 0.0_f64;
#[cfg(not(feature = "std"))]
#[inline(always)]
pub(crate) fn floor(f: f64) -> f64 {
unsafe { core::intrinsics::floorf64(f) }
}
#[cfg(not(feature = "std"))]
#[inline(always)]
pub(crate) fn ln(f: f64) -> f64 {
unsafe { core::intrinsics::logf64(f) }
}
#[cfg(not(feature = "std"))]
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn powi(f: f64, i: i32) -> f64 {
unsafe { core::intrinsics::powif64(f, i) }
}
#[cfg(feature = "std")]
#[inline(always)]
pub(crate) fn floor(f: f64) -> f64 {
f.floor()
}
#[cfg(feature = "std")]
#[inline(always)]
pub(crate) fn ln(f: f64) -> f64 {
f.ln()
}
#[cfg(feature = "std")]
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn powi(f: f64, i: i32) -> f64 {
f.powi(i)
}
macro_rules! absv {
($n:expr) => ({
let n = $n;
if n < 0 { -n } else { n }
})
}
macro_rules! maxv {
($a:expr, $b:expr) => ({
let a = $a;
let b = $b;
if a > b { a } else { b }
})
}
macro_rules! minv {
($a:expr, $b:expr) => ({
let a = $a;
let b = $b;
if a < b { a } else { b }
})
}
#[inline(always)]
#[allow(dead_code)]
pub(crate) unsafe extern "C" fn reverse(first: *mut u8, last: *mut u8) {
let mut f = first;
let mut l = last;
let mut x: u8;
let mut li = l.sub(1);
while f != l && f != li {
l = li;
x = *f;
*f = *l;
*l = x;
li = l.sub(1);
f = f.add(1);
}
}
#[inline(always)]
#[allow(dead_code)]
pub(crate) unsafe extern "C" fn distance(first: *const u8, last: *const u8)
-> usize
{
debug_assert!(last >= first, "range must be positive.");
let f = first as usize;
let l = last as usize;
l - f
}
extern {
fn memcmp(l: *const u8, r: *const u8, n: usize) -> i32;
}
#[inline(always)]
#[allow(dead_code)]
pub(crate) unsafe extern "C" fn equal_to(l: *const u8, r: *const u8, n: usize)
-> bool
{
memcmp(l, r, n) == 0
}
#[inline(always)]
#[allow(dead_code)]
pub(crate) unsafe extern "C" fn starts_with(l: *const u8, ln: usize, r: *const u8, rn: usize)
-> bool
{
ln >= rn && equal_to(l, r, rn)
}
#[inline(always)]
#[allow(dead_code)]
pub(crate) unsafe extern "C" fn ends_with(l: *const u8, ln: usize, r: *const u8, rn: usize)
-> bool
{
ln >= rn && equal_to(l.add(ln - rn), r, rn)
}
#[doc(hidden)]
macro_rules! bytes_impl {
($func:ident, $t:ty, $callback:ident) => (
#[inline]
pub fn $func(bytes: &[u8], base: u8)
-> $t
{
unsafe {
let first = bytes.as_ptr();
let last = first.add(bytes.len());
let (value, _) = $callback(first, last, base);
value
}
}
)
}
#[doc(hidden)]
macro_rules! try_bytes_impl {
($func:ident, $t:ty, $callback:ident) => (
#[inline]
pub fn $func(bytes: &[u8], base: u8)
-> Result<$t, usize>
{
unsafe {
let first = bytes.as_ptr();
let last = first.add(bytes.len());
let (value, p) = $callback(first, last, base);
match p == last {
true => Ok(value),
_ => Err(match p == ptr::null() {
true => 0, false => distance(first, p),
}),
}
}
}
)
}
#[cfg(any(feature = "std", feature = "alloc"))]
macro_rules! string_impl {
($func:ident, $t:ty, $callback:ident, $capacity:expr) => (
#[inline]
pub fn $func(value: $t, base: u8)
-> String
{
let mut buf: Vec<u8> = Vec::with_capacity($capacity);
unsafe {
let first: *mut u8 = buf.as_mut_ptr();
let last = first.add(buf.capacity());
let end = $callback(value, first, last, base);
let size = distance(first, end);
buf.set_len(size);
String::from_utf8_unchecked(buf)
}
}
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reverse_test() {
unsafe {
let mut x: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let y: [u8; 10] = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
let first: *mut u8 = x.as_mut_ptr();
let last = first.add(x.len());
reverse(first, last);
assert_eq!(x, y);
}
}
#[test]
fn distance_test() {
unsafe {
let x: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let first: *const u8 = x.as_ptr();
let last = first.add(x.len());
assert_eq!(distance(first, last), 10);
}
}
#[test]
fn equal_to_test() {
unsafe {
let x = "Hello";
let y = "Hello";
let z = "hello";
assert!(equal_to(x.as_ptr(), y.as_ptr(), x.len()));
assert!(!equal_to(x.as_ptr(), z.as_ptr(), x.len()));
assert!(!equal_to(y.as_ptr(), z.as_ptr(), x.len()));
}
}
#[test]
fn starts_with_test() {
unsafe {
let x = "Hello";
let y = "H";
let z = "h";
assert!(starts_with(x.as_ptr(), x.len(), y.as_ptr(), y.len()));
assert!(!starts_with(x.as_ptr(), x.len(), z.as_ptr(), z.len()));
assert!(!starts_with(y.as_ptr(), y.len(), z.as_ptr(), z.len()));
assert!(!starts_with(y.as_ptr(), y.len(), x.as_ptr(), x.len()));
assert!(!starts_with(z.as_ptr(), z.len(), x.as_ptr(), x.len()));
}
}
#[test]
fn ends_with_test() {
unsafe {
let w = "Hello";
let x = "lO";
let y = "lo";
let z = "o";
assert!(!ends_with(w.as_ptr(), w.len(), x.as_ptr(), x.len()));
assert!(ends_with(w.as_ptr(), w.len(), y.as_ptr(), y.len()));
assert!(ends_with(w.as_ptr(), w.len(), z.as_ptr(), z.len()));
assert!(!ends_with(x.as_ptr(), x.len(), y.as_ptr(), y.len()));
assert!(!ends_with(x.as_ptr(), x.len(), z.as_ptr(), z.len()));
assert!(ends_with(y.as_ptr(), y.len(), z.as_ptr(), z.len()));
assert!(!ends_with(z.as_ptr(), z.len(), y.as_ptr(), y.len()));
assert!(!ends_with(z.as_ptr(), z.len(), x.as_ptr(), x.len()));
assert!(!ends_with(z.as_ptr(), z.len(), w.as_ptr(), w.len()));
assert!(!ends_with(y.as_ptr(), y.len(), x.as_ptr(), x.len()));
assert!(!ends_with(y.as_ptr(), y.len(), w.as_ptr(), w.len()));
assert!(!ends_with(x.as_ptr(), x.len(), w.as_ptr(), w.len()));
}
}
}