<commit_before>#[doc = "Operations and constants for `uint`"];

/*
Module: uint
*/

/*
Const: min_value

Return the minimal value for an uint.

This is always 0
*/
const min_value: uint = 0u;

/*
Const: max_value

Return the maximal value for an uint.

This is 2^wordsize - 1
*/
const max_value: uint = 0u - 1u;

/*
Function: max
*/
fn max(x: uint, y: uint) -> uint {
    if x > y { x } else { y }
}

/*
Function: min
*/
fn min(x: uint, y: uint) -> uint {
    if x < y { x } else { y }
}

/* Function: add */
pure fn add(x: uint, y: uint) -> uint { ret x + y; }

/* Function: sub */
pure fn sub(x: uint, y: uint) -> uint { ret x - y; }

/* Function: mul */
pure fn mul(x: uint, y: uint) -> uint { ret x * y; }

/* Function: div */
pure fn div(x: uint, y: uint) -> uint { ret x / y; }

/* Function: div_ceil

   Divide two numbers, return the result, rounded up.

   Parameters:
   x - an integer
   y - an integer distinct from 0u

   Return:
    The smallest integer `q` such that `x/y <= q`.
*/
pure fn div_ceil(x: uint, y: uint) -> uint {
    let div = div(x, y);
    if x % y == 0u { ret div;}
    else { ret div + 1u; }
}

/* Function: div_ceil

   Divide two numbers, return the result, rounded to the closest integer.

   Parameters:
   x - an integer
   y - an integer distinct from 0u

   Return:
    The integer `q` closest to `x/y`.
*/
pure fn div_round(x: uint, y: uint) -> uint {
    let div = div(x, y);
    if x % y * 2u  < y { ret div;}
    else { ret div + 1u; }
}

/* Function: div_ceil

   Divide two numbers, return the result, rounded down.

   Parameters:
   x - an integer
   y - an integer distinct from 0u

   Note: This is the same function as `div`.

   Return:
    The smallest integer `q` such that `x/y <= q`. This
   is either `x/y` or `x/y + 1`.
*/
pure fn div_floor(x: uint, y: uint) -> uint { ret x / y; }

/* Function: rem */
pure fn rem(x: uint, y: uint) -> uint { ret x % y; }

/* Predicate: lt */
pure fn lt(x: uint, y: uint) -> bool { ret x < y; }

/* Predicate: le */
pure fn le(x: uint, y: uint) -> bool { ret x <= y; }

/* Predicate: eq */
pure fn eq(x: uint, y: uint) -> bool { ret x == y; }

/* Predicate: ne */
pure fn ne(x: uint, y: uint) -> bool { ret x != y; }

/* Predicate: ge */
pure fn ge(x: uint, y: uint) -> bool { ret x >= y; }

/* Predicate: gt */
pure fn gt(x: uint, y: uint) -> bool { ret x > y; }

/*
Function: hash

Produce a uint suitable for use in a hash table
*/
fn hash(x: uint) -> uint { ret x; }

/*
Function: range

Iterate over the range [`lo`..`hi`)
*/
fn range(lo: uint, hi: uint, it: fn(uint)) {
    let i = lo;
    while i < hi { it(i); i += 1u; }
}

/*
Function: loop

Iterate over the range [`lo`..`hi`), or stop when requested

Parameters:
lo - The integer at which to start the loop (included)
hi - The integer at which to stop the loop (excluded)
it - A block to execute with each consecutive integer of the range.
Return `true` to continue, `false` to stop.

Returns:

`true` If execution proceeded correctly, `false` if it was interrupted,
that is if `it` returned `false` at any point.
*/
fn loop(lo: uint, hi: uint, it: fn(uint) -> bool) -> bool {
    let i = lo;
    while i < hi {
        if (!it(i)) { ret false; }
        i += 1u;
    }
    ret true;
}

/*
Function: next_power_of_two

Returns the smallest power of 2 greater than or equal to `n`
*/
fn next_power_of_two(n: uint) -> uint {
    let halfbits: uint = sys::size_of::<uint>() * 4u;
    let tmp: uint = n - 1u;
    let shift: uint = 1u;
    while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
    ret tmp + 1u;
}

/*
Function: parse_buf

Parse a buffer of bytes

Parameters:

buf - A byte buffer
radix - The base of the number

Failure:

buf must not be empty
*/
fn parse_buf(buf: [u8], radix: uint) -> uint {
    if vec::len::<u8>(buf) == 0u {
        #error("parse_buf(): buf is empty");
        fail;
    }
    let i = vec::len::<u8>(buf) - 1u;
    let power = 1u;
    let n = 0u;
    while true {
        let digit = char::to_digit(buf[i] as char);
        if (digit as uint) >= radix {
            fail;
        }
        n += (digit as uint) * power;
        power *= radix;
        if i == 0u { ret n; }
        i -= 1u;
    }
    fail;
}

/*
Function: from_str

Parse a string to an int

Failure:

s must not be empty
*/
fn from_str(s: str) -> uint { parse_buf(str::bytes(s), 10u) }

/*
Function: to_str

Convert to a string in a given base
*/
fn to_str(num: uint, radix: uint) -> str {
    let n = num;
    assert (0u < radix && radix <= 16u);
    fn digit(n: uint) -> char {
        ret alt n {
              0u { '0' }
              1u { '1' }
              2u { '2' }
              3u { '3' }
              4u { '4' }
              5u { '5' }
              6u { '6' }
              7u { '7' }
              8u { '8' }
              9u { '9' }
              10u { 'a' }
              11u { 'b' }
              12u { 'c' }
              13u { 'd' }
              14u { 'e' }
              15u { 'f' }
              _ { fail }
            };
    }
    if n == 0u { ret "0"; }
    let s: str = "";
    while n != 0u {
        s += str::from_byte(digit(n % radix) as u8);
        n /= radix;
    }
    let s1: str = "";
    let len: uint = str::byte_len(s);
    while len != 0u { len -= 1u; s1 += str::from_byte(s[len]); }
    ret s1;
}

/*
Function: str

Convert to a string
*/
fn str(i: uint) -> str { ret to_str(i, 10u); }

/*
Function: compl

Computes the bitwise complement.
*/
fn compl(i: uint) -> uint {
    uint::max_value ^ i
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_from_str() {
        assert (uint::from_str("0") == 0u);
        assert (uint::from_str("3") == 3u);
        assert (uint::from_str("10") == 10u);
        assert (uint::from_str("123456789") == 123456789u);
        assert (uint::from_str("00100") == 100u);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_from_str_fail_1() {
        uint::from_str(" ");
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_from_str_fail_2() {
        uint::from_str("x");
    }

    #[test]
    fn test_parse_buf() {
        import str::bytes;
        assert (uint::parse_buf(bytes("123"), 10u) == 123u);
        assert (uint::parse_buf(bytes("1001"), 2u) == 9u);
        assert (uint::parse_buf(bytes("123"), 8u) == 83u);
        assert (uint::parse_buf(bytes("123"), 16u) == 291u);
        assert (uint::parse_buf(bytes("ffff"), 16u) == 65535u);
        assert (uint::parse_buf(bytes("z"), 36u) == 35u);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_parse_buf_fail_1() {
        uint::parse_buf(str::bytes("Z"), 10u);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_parse_buf_fail_2() {
        uint::parse_buf(str::bytes("_"), 2u);
    }

    #[test]
    fn test_next_power_of_two() {
        assert (uint::next_power_of_two(0u) == 0u);
        assert (uint::next_power_of_two(1u) == 1u);
        assert (uint::next_power_of_two(2u) == 2u);
        assert (uint::next_power_of_two(3u) == 4u);
        assert (uint::next_power_of_two(4u) == 4u);
        assert (uint::next_power_of_two(5u) == 8u);
        assert (uint::next_power_of_two(6u) == 8u);
        assert (uint::next_power_of_two(7u) == 8u);
        assert (uint::next_power_of_two(8u) == 8u);
        assert (uint::next_power_of_two(9u) == 16u);
        assert (uint::next_power_of_two(10u) == 16u);
        assert (uint::next_power_of_two(11u) == 16u);
        assert (uint::next_power_of_two(12u) == 16u);
        assert (uint::next_power_of_two(13u) == 16u);
        assert (uint::next_power_of_two(14u) == 16u);
        assert (uint::next_power_of_two(15u) == 16u);
        assert (uint::next_power_of_two(16u) == 16u);
        assert (uint::next_power_of_two(17u) == 32u);
        assert (uint::next_power_of_two(18u) == 32u);
        assert (uint::next_power_of_two(19u) == 32u);
        assert (uint::next_power_of_two(20u) == 32u);
        assert (uint::next_power_of_two(21u) == 32u);
        assert (uint::next_power_of_two(22u) == 32u);
        assert (uint::next_power_of_two(23u) == 32u);
        assert (uint::next_power_of_two(24u) == 32u);
        assert (uint::next_power_of_two(25u) == 32u);
        assert (uint::next_power_of_two(26u) == 32u);
        assert (uint::next_power_of_two(27u) == 32u);
        assert (uint::next_power_of_two(28u) == 32u);
        assert (uint::next_power_of_two(29u) == 32u);
        assert (uint::next_power_of_two(30u) == 32u);
        assert (uint::next_power_of_two(31u) == 32u);
        assert (uint::next_power_of_two(32u) == 32u);
        assert (uint::next_power_of_two(33u) == 64u);
        assert (uint::next_power_of_two(34u) == 64u);
        assert (uint::next_power_of_two(35u) == 64u);
        assert (uint::next_power_of_two(36u) == 64u);
        assert (uint::next_power_of_two(37u) == 64u);
        assert (uint::next_power_of_two(38u) == 64u);
        assert (uint::next_power_of_two(39u) == 64u);
    }

    #[test]
    fn test_overflows() {
        assert (uint::max_value > 0u);
        assert (uint::min_value <= 0u);
        assert (uint::min_value + uint::max_value + 1u == 0u);
    }

    #[test]
    fn test_div() {
        assert(uint::div_floor(3u, 4u) == 0u);
        assert(uint::div_ceil(3u, 4u)  == 1u);
        assert(uint::div_round(3u, 4u) == 1u);
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>core: Make uint::min/max pure<commit_after>#[doc = "Operations and constants for `uint`"];

/*
Module: uint
*/

/*
Const: min_value

Return the minimal value for an uint.

This is always 0
*/
const min_value: uint = 0u;

/*
Const: max_value

Return the maximal value for an uint.

This is 2^wordsize - 1
*/
const max_value: uint = 0u - 1u;

/*
Function: max
*/
pure fn max(x: uint, y: uint) -> uint {
    if x > y { x } else { y }
}

/*
Function: min
*/
pure fn min(x: uint, y: uint) -> uint {
    if x < y { x } else { y }
}

/* Function: add */
pure fn add(x: uint, y: uint) -> uint { ret x + y; }

/* Function: sub */
pure fn sub(x: uint, y: uint) -> uint { ret x - y; }

/* Function: mul */
pure fn mul(x: uint, y: uint) -> uint { ret x * y; }

/* Function: div */
pure fn div(x: uint, y: uint) -> uint { ret x / y; }

/* Function: div_ceil

   Divide two numbers, return the result, rounded up.

   Parameters:
   x - an integer
   y - an integer distinct from 0u

   Return:
    The smallest integer `q` such that `x/y <= q`.
*/
pure fn div_ceil(x: uint, y: uint) -> uint {
    let div = div(x, y);
    if x % y == 0u { ret div;}
    else { ret div + 1u; }
}

/* Function: div_ceil

   Divide two numbers, return the result, rounded to the closest integer.

   Parameters:
   x - an integer
   y - an integer distinct from 0u

   Return:
    The integer `q` closest to `x/y`.
*/
pure fn div_round(x: uint, y: uint) -> uint {
    let div = div(x, y);
    if x % y * 2u  < y { ret div;}
    else { ret div + 1u; }
}

/* Function: div_ceil

   Divide two numbers, return the result, rounded down.

   Parameters:
   x - an integer
   y - an integer distinct from 0u

   Note: This is the same function as `div`.

   Return:
    The smallest integer `q` such that `x/y <= q`. This
   is either `x/y` or `x/y + 1`.
*/
pure fn div_floor(x: uint, y: uint) -> uint { ret x / y; }

/* Function: rem */
pure fn rem(x: uint, y: uint) -> uint { ret x % y; }

/* Predicate: lt */
pure fn lt(x: uint, y: uint) -> bool { ret x < y; }

/* Predicate: le */
pure fn le(x: uint, y: uint) -> bool { ret x <= y; }

/* Predicate: eq */
pure fn eq(x: uint, y: uint) -> bool { ret x == y; }

/* Predicate: ne */
pure fn ne(x: uint, y: uint) -> bool { ret x != y; }

/* Predicate: ge */
pure fn ge(x: uint, y: uint) -> bool { ret x >= y; }

/* Predicate: gt */
pure fn gt(x: uint, y: uint) -> bool { ret x > y; }

/*
Function: hash

Produce a uint suitable for use in a hash table
*/
fn hash(x: uint) -> uint { ret x; }

/*
Function: range

Iterate over the range [`lo`..`hi`)
*/
fn range(lo: uint, hi: uint, it: fn(uint)) {
    let i = lo;
    while i < hi { it(i); i += 1u; }
}

/*
Function: loop

Iterate over the range [`lo`..`hi`), or stop when requested

Parameters:
lo - The integer at which to start the loop (included)
hi - The integer at which to stop the loop (excluded)
it - A block to execute with each consecutive integer of the range.
Return `true` to continue, `false` to stop.

Returns:

`true` If execution proceeded correctly, `false` if it was interrupted,
that is if `it` returned `false` at any point.
*/
fn loop(lo: uint, hi: uint, it: fn(uint) -> bool) -> bool {
    let i = lo;
    while i < hi {
        if (!it(i)) { ret false; }
        i += 1u;
    }
    ret true;
}

/*
Function: next_power_of_two

Returns the smallest power of 2 greater than or equal to `n`
*/
fn next_power_of_two(n: uint) -> uint {
    let halfbits: uint = sys::size_of::<uint>() * 4u;
    let tmp: uint = n - 1u;
    let shift: uint = 1u;
    while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
    ret tmp + 1u;
}

/*
Function: parse_buf

Parse a buffer of bytes

Parameters:

buf - A byte buffer
radix - The base of the number

Failure:

buf must not be empty
*/
fn parse_buf(buf: [u8], radix: uint) -> uint {
    if vec::len::<u8>(buf) == 0u {
        #error("parse_buf(): buf is empty");
        fail;
    }
    let i = vec::len::<u8>(buf) - 1u;
    let power = 1u;
    let n = 0u;
    while true {
        let digit = char::to_digit(buf[i] as char);
        if (digit as uint) >= radix {
            fail;
        }
        n += (digit as uint) * power;
        power *= radix;
        if i == 0u { ret n; }
        i -= 1u;
    }
    fail;
}

/*
Function: from_str

Parse a string to an int

Failure:

s must not be empty
*/
fn from_str(s: str) -> uint { parse_buf(str::bytes(s), 10u) }

/*
Function: to_str

Convert to a string in a given base
*/
fn to_str(num: uint, radix: uint) -> str {
    let n = num;
    assert (0u < radix && radix <= 16u);
    fn digit(n: uint) -> char {
        ret alt n {
              0u { '0' }
              1u { '1' }
              2u { '2' }
              3u { '3' }
              4u { '4' }
              5u { '5' }
              6u { '6' }
              7u { '7' }
              8u { '8' }
              9u { '9' }
              10u { 'a' }
              11u { 'b' }
              12u { 'c' }
              13u { 'd' }
              14u { 'e' }
              15u { 'f' }
              _ { fail }
            };
    }
    if n == 0u { ret "0"; }
    let s: str = "";
    while n != 0u {
        s += str::from_byte(digit(n % radix) as u8);
        n /= radix;
    }
    let s1: str = "";
    let len: uint = str::byte_len(s);
    while len != 0u { len -= 1u; s1 += str::from_byte(s[len]); }
    ret s1;
}

/*
Function: str

Convert to a string
*/
fn str(i: uint) -> str { ret to_str(i, 10u); }

/*
Function: compl

Computes the bitwise complement.
*/
fn compl(i: uint) -> uint {
    uint::max_value ^ i
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_from_str() {
        assert (uint::from_str("0") == 0u);
        assert (uint::from_str("3") == 3u);
        assert (uint::from_str("10") == 10u);
        assert (uint::from_str("123456789") == 123456789u);
        assert (uint::from_str("00100") == 100u);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_from_str_fail_1() {
        uint::from_str(" ");
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_from_str_fail_2() {
        uint::from_str("x");
    }

    #[test]
    fn test_parse_buf() {
        import str::bytes;
        assert (uint::parse_buf(bytes("123"), 10u) == 123u);
        assert (uint::parse_buf(bytes("1001"), 2u) == 9u);
        assert (uint::parse_buf(bytes("123"), 8u) == 83u);
        assert (uint::parse_buf(bytes("123"), 16u) == 291u);
        assert (uint::parse_buf(bytes("ffff"), 16u) == 65535u);
        assert (uint::parse_buf(bytes("z"), 36u) == 35u);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_parse_buf_fail_1() {
        uint::parse_buf(str::bytes("Z"), 10u);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_parse_buf_fail_2() {
        uint::parse_buf(str::bytes("_"), 2u);
    }

    #[test]
    fn test_next_power_of_two() {
        assert (uint::next_power_of_two(0u) == 0u);
        assert (uint::next_power_of_two(1u) == 1u);
        assert (uint::next_power_of_two(2u) == 2u);
        assert (uint::next_power_of_two(3u) == 4u);
        assert (uint::next_power_of_two(4u) == 4u);
        assert (uint::next_power_of_two(5u) == 8u);
        assert (uint::next_power_of_two(6u) == 8u);
        assert (uint::next_power_of_two(7u) == 8u);
        assert (uint::next_power_of_two(8u) == 8u);
        assert (uint::next_power_of_two(9u) == 16u);
        assert (uint::next_power_of_two(10u) == 16u);
        assert (uint::next_power_of_two(11u) == 16u);
        assert (uint::next_power_of_two(12u) == 16u);
        assert (uint::next_power_of_two(13u) == 16u);
        assert (uint::next_power_of_two(14u) == 16u);
        assert (uint::next_power_of_two(15u) == 16u);
        assert (uint::next_power_of_two(16u) == 16u);
        assert (uint::next_power_of_two(17u) == 32u);
        assert (uint::next_power_of_two(18u) == 32u);
        assert (uint::next_power_of_two(19u) == 32u);
        assert (uint::next_power_of_two(20u) == 32u);
        assert (uint::next_power_of_two(21u) == 32u);
        assert (uint::next_power_of_two(22u) == 32u);
        assert (uint::next_power_of_two(23u) == 32u);
        assert (uint::next_power_of_two(24u) == 32u);
        assert (uint::next_power_of_two(25u) == 32u);
        assert (uint::next_power_of_two(26u) == 32u);
        assert (uint::next_power_of_two(27u) == 32u);
        assert (uint::next_power_of_two(28u) == 32u);
        assert (uint::next_power_of_two(29u) == 32u);
        assert (uint::next_power_of_two(30u) == 32u);
        assert (uint::next_power_of_two(31u) == 32u);
        assert (uint::next_power_of_two(32u) == 32u);
        assert (uint::next_power_of_two(33u) == 64u);
        assert (uint::next_power_of_two(34u) == 64u);
        assert (uint::next_power_of_two(35u) == 64u);
        assert (uint::next_power_of_two(36u) == 64u);
        assert (uint::next_power_of_two(37u) == 64u);
        assert (uint::next_power_of_two(38u) == 64u);
        assert (uint::next_power_of_two(39u) == 64u);
    }

    #[test]
    fn test_overflows() {
        assert (uint::max_value > 0u);
        assert (uint::min_value <= 0u);
        assert (uint::min_value + uint::max_value + 1u == 0u);
    }

    #[test]
    fn test_div() {
        assert(uint::div_floor(3u, 4u) == 0u);
        assert(uint::div_ceil(3u, 4u)  == 1u);
        assert(uint::div_round(3u, 4u) == 1u);
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>use core::{
    cell::UnsafeCell,
    fmt,
    ops::{Deref, DerefMut},
    sync::atomic::{spin_loop_hint as cpu_relax, AtomicUsize, Ordering},
};

/// A ticket lock for mutual exclusion based on spinning.
///
/// A ticket lock is similair to a queue management system.
/// When a thread tries to lock the values,
/// it is assigned a ticket, and it spins until its ticket is the next in line.
/// When releasing the value, the next ticket will be processed.
pub struct TicketMutex<T: ?Sized> {
    pub(crate) next_ticket: AtomicUsize,
    pub(crate) next_serving: AtomicUsize,
    value: UnsafeCell<T>,
}

/// A guard that protects some data.
///
/// When the guard is dropped, the next ticket will be processed.
pub struct TicketMutexGuard<'a, T: ?Sized + 'a> {
    next_serving: &'a AtomicUsize,
    ticket: usize,
    value: &'a mut T,
}

impl<'a, T: ?Sized> TicketMutexGuard<'a, T> {
    /// Leak the lock guard, yielding a mutable reference to the underlying data.
    ///
    /// Note that this function will permanently lock the original lock.
    ///
    /// ```
    /// let mylock = spin::Mutex::new(0);
    ///
    /// let data: &mut i32 = spin::MutexGuard::leak(mylock.lock());
    ///
    /// *data = 1;
    /// assert_eq!(*data, 1);
    /// ```
    #[inline]
    pub fn leak(this: Self) -> &'a mut T {
        let data = this.value as *mut _; // Keep it in pointer form temporarily to avoid double-aliasing
        core::mem::forget(this);
        unsafe { &mut *data }
    }
}

unsafe impl<T: ?Sized + Send> Sync for TicketMutex<T> {}
unsafe impl<T: ?Sized + Send> Send for TicketMutex<T> {}

impl<T> TicketMutex<T> {
    /// Creates a new `TicketMutex` that wraps the given value.
    ///
    /// This method can be used in static context.
    ///
    /// ```
    /// static LOCK: spin::mutex::TicketMutex<i32> = spin::mutex::TicketMutex::new(123);
    ///
    /// # fn main() {
    /// let value = LOCK.lock();
    /// assert_eq!(*value, 123);
    /// drop(value);
    /// # }
    /// ```
    pub const fn new(value: T) -> Self {
        Self {
            next_ticket: AtomicUsize::new(0),
            next_serving: AtomicUsize::new(0),
            value: UnsafeCell::new(value),
        }
    }

    /// Unwraps the inner value of this lock.
    pub fn into_inner(self) -> T {
        self.value.into_inner()
    }
}

impl<T: ?Sized + fmt::Debug> fmt::Debug for TicketMutex<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.try_lock() {
            Some(guard) => write!(f, "Mutex {{ data: ")
                .and_then(|()| (&*guard).fmt(f))
                .and_then(|()| write!(f, "}}")),
            None => write!(f, "Mutex {{ <locked> }}"),
        }
    }
}

impl<T: ?Sized> TicketMutex<T> {
    #[allow(dead_code)]
    pub(crate) fn is_locked(&self) -> bool {
        let ticket = self.next_ticket.load(Ordering::Relaxed) + 1;
        self.next_serving.load(Ordering::Relaxed) != ticket
    }

    /// Spins the thread until the value can be locked.
    ///
    /// The returned value can be used to modify the value,
    /// and will be unlocked after dropping the return value.
    pub fn lock(&self) -> TicketMutexGuard<T> {
        let ticket = self.next_ticket.fetch_add(1, Ordering::Relaxed);

        while self.next_serving.load(Ordering::Acquire) != ticket {
            cpu_relax();
        }

        TicketMutexGuard {
            next_serving: &self.next_serving,
            ticket,
            // Safety
            // We know that we are the next ticket to be served,
            // so there's no other thread accessing the value.
            //
            // Every other thread has another ticket number so it's
            // definitely stuck in the spin loop above.
            value: unsafe { &mut *self.value.get() },
        }
    }

    /// Force unlock the ticket lock, by serving the next ticket.
    ///
    /// # Safety
    ///
    /// This is *extremely* unsafe if the lock is not held by the current
    /// thread. However, this can be useful in some instances for exposing the
    /// lock to FFI that doesn't know how to deal with RAII.
    pub unsafe fn force_unlock(&self) {
        self.next_serving.fetch_add(1, Ordering::Release);
    }

    /// Tries to lock this lock. If it's already locked, `None` is returned,
    /// otherwise a guard that protects the data is returned.
    pub fn try_lock(&self) -> Option<TicketMutexGuard<T>> {
        let ticket = self
            .next_ticket
            .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |ticket| {
                if self.next_serving.load(Ordering::Acquire) == ticket {
                    Some(ticket + 1)
                } else {
                    None
                }
            });

        ticket.ok().map(|ticket| TicketMutexGuard {
            next_serving: &self.next_serving,
            ticket,
            // Safety
            // We have a ticket that is equal to the next_serving ticket, so we know:
            // - that no other thread can have the same ticket id as this thread
            // - that we are the next one to be served so we have exclusive access to the value
            value: unsafe { &mut *self.value.get() },
        })
    }

    /// Returns a mutable reference to the underlying data.
    ///
    /// This will not lock this lock, since this method borrows
    /// this lock mutably so no locking is needed.
    pub fn get_mut(&mut self) -> &mut T {
        // Safety:
        // We know that there are no other references to `self`,
        // so it's safe to return a exclusive reference to the value.
        unsafe { &mut *self.value.get() }
    }
}

impl<T> From<T> for TicketMutex<T> {
    fn from(value: T) -> Self {
        Self::new(value)
    }
}

impl<T: ?Sized + Default> Default for TicketMutex<T> {
    fn default() -> TicketMutex<T> {
        TicketMutex::new(Default::default())
    }
}

impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for TicketMutexGuard<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

impl<'a, T: ?Sized + fmt::Display> fmt::Display for TicketMutexGuard<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl<'a, T: ?Sized> Deref for TicketMutexGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        self.value
    }
}

impl<'a, T: ?Sized> DerefMut for TicketMutexGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        self.value
    }
}

impl<'a, T: ?Sized> Drop for TicketMutexGuard<'a, T> {
    fn drop(&mut self) {
        let new_ticket = self.ticket + 1;
        self.next_serving.store(new_ticket, Ordering::Release);
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::v1::*;

    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::sync::mpsc::channel;
    use std::sync::Arc;
    use std::thread;

    use super::*;

    #[derive(Eq, PartialEq, Debug)]
    struct NonCopy(i32);

    #[test]
    fn smoke() {
        let m = TicketMutex::new(());
        drop(m.lock());
        drop(m.lock());
    }

    #[test]
    fn lots_and_lots() {
        static M: TicketMutex<()> = TicketMutex::new(());
        static mut CNT: u32 = 0;
        const J: u32 = 1000;
        const K: u32 = 3;

        fn inc() {
            for _ in 0..J {
                unsafe {
                    let _g = M.lock();
                    CNT += 1;
                }
            }
        }

        let (tx, rx) = channel();
        for _ in 0..K {
            let tx2 = tx.clone();
            thread::spawn(move || {
                inc();
                tx2.send(()).unwrap();
            });
            let tx2 = tx.clone();
            thread::spawn(move || {
                inc();
                tx2.send(()).unwrap();
            });
        }

        drop(tx);
        for _ in 0..2 * K {
            rx.recv().unwrap();
        }
        assert_eq!(unsafe { CNT }, J * K * 2);
    }

    #[test]
    fn try_lock() {
        let mutex = TicketMutex::new(42);

        // First lock succeeds
        let a = mutex.try_lock();
        assert_eq!(a.as_ref().map(|r| **r), Some(42));

        // Additional lock failes
        let b = mutex.try_lock();
        assert!(b.is_none());

        // After dropping lock, it succeeds again
        ::core::mem::drop(a);
        let c = mutex.try_lock();
        assert_eq!(c.as_ref().map(|r| **r), Some(42));
    }

    #[test]
    fn test_into_inner() {
        let m = TicketMutex::new(NonCopy(10));
        assert_eq!(m.into_inner(), NonCopy(10));
    }

    #[test]
    fn test_into_inner_drop() {
        struct Foo(Arc<AtomicUsize>);
        impl Drop for Foo {
            fn drop(&mut self) {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }
        let num_drops = Arc::new(AtomicUsize::new(0));
        let m = TicketMutex::new(Foo(num_drops.clone()));
        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        {
            let _inner = m.into_inner();
            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        }
        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
    }

    #[test]
    fn test_mutex_arc_nested() {
        // Tests nested mutexes and access
        // to underlying data.
        let arc = Arc::new(TicketMutex::new(1));
        let arc2 = Arc::new(TicketMutex::new(arc));
        let (tx, rx) = channel();
        let _t = thread::spawn(move || {
            let lock = arc2.lock();
            let lock2 = lock.lock();
            assert_eq!(*lock2, 1);
            tx.send(()).unwrap();
        });
        rx.recv().unwrap();
    }

    #[test]
    fn test_mutex_arc_access_in_unwind() {
        let arc = Arc::new(TicketMutex::new(1));
        let arc2 = arc.clone();
        let _ = thread::spawn(move || -> () {
            struct Unwinder {
                i: Arc<TicketMutex<i32>>,
            }
            impl Drop for Unwinder {
                fn drop(&mut self) {
                    *self.i.lock() += 1;
                }
            }
            let _u = Unwinder { i: arc2 };
            panic!();
        })
        .join();
        let lock = arc.lock();
        assert_eq!(*lock, 2);
    }

    #[test]
    fn test_mutex_unsized() {
        let mutex: &TicketMutex<[i32]> = &TicketMutex::new([1, 2, 3]);
        {
            let b = &mut *mutex.lock();
            b[0] = 4;
            b[2] = 5;
        }
        let comp: &[i32] = &[4, 2, 5];
        assert_eq!(&*mutex.lock(), comp);
    }
}
<commit_msg>Add test for TicketLock::is_locked<commit_after>use core::{
    cell::UnsafeCell,
    fmt,
    ops::{Deref, DerefMut},
    sync::atomic::{spin_loop_hint as cpu_relax, AtomicUsize, Ordering},
};

/// A ticket lock for mutual exclusion based on spinning.
///
/// A ticket lock is similair to a queue management system.
/// When a thread tries to lock the values,
/// it is assigned a ticket, and it spins until its ticket is the next in line.
/// When releasing the value, the next ticket will be processed.
pub struct TicketMutex<T: ?Sized> {
    pub(crate) next_ticket: AtomicUsize,
    pub(crate) next_serving: AtomicUsize,
    value: UnsafeCell<T>,
}

/// A guard that protects some data.
///
/// When the guard is dropped, the next ticket will be processed.
pub struct TicketMutexGuard<'a, T: ?Sized + 'a> {
    next_serving: &'a AtomicUsize,
    ticket: usize,
    value: &'a mut T,
}

impl<'a, T: ?Sized> TicketMutexGuard<'a, T> {
    /// Leak the lock guard, yielding a mutable reference to the underlying data.
    ///
    /// Note that this function will permanently lock the original lock.
    ///
    /// ```
    /// let mylock = spin::Mutex::new(0);
    ///
    /// let data: &mut i32 = spin::MutexGuard::leak(mylock.lock());
    ///
    /// *data = 1;
    /// assert_eq!(*data, 1);
    /// ```
    #[inline]
    pub fn leak(this: Self) -> &'a mut T {
        let data = this.value as *mut _; // Keep it in pointer form temporarily to avoid double-aliasing
        core::mem::forget(this);
        unsafe { &mut *data }
    }
}

unsafe impl<T: ?Sized + Send> Sync for TicketMutex<T> {}
unsafe impl<T: ?Sized + Send> Send for TicketMutex<T> {}

impl<T> TicketMutex<T> {
    /// Creates a new `TicketMutex` that wraps the given value.
    ///
    /// This method can be used in static context.
    ///
    /// ```
    /// static LOCK: spin::mutex::TicketMutex<i32> = spin::mutex::TicketMutex::new(123);
    ///
    /// # fn main() {
    /// let value = LOCK.lock();
    /// assert_eq!(*value, 123);
    /// drop(value);
    /// # }
    /// ```
    pub const fn new(value: T) -> Self {
        Self {
            next_ticket: AtomicUsize::new(0),
            next_serving: AtomicUsize::new(0),
            value: UnsafeCell::new(value),
        }
    }

    /// Unwraps the inner value of this lock.
    pub fn into_inner(self) -> T {
        self.value.into_inner()
    }
}

impl<T: ?Sized + fmt::Debug> fmt::Debug for TicketMutex<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.try_lock() {
            Some(guard) => write!(f, "Mutex {{ data: ")
                .and_then(|()| (&*guard).fmt(f))
                .and_then(|()| write!(f, "}}")),
            None => write!(f, "Mutex {{ <locked> }}"),
        }
    }
}

impl<T: ?Sized> TicketMutex<T> {
    #[allow(dead_code)]
    pub(crate) fn is_locked(&self) -> bool {
        let ticket = self.next_ticket.load(Ordering::Relaxed);
        self.next_serving.load(Ordering::Relaxed) != ticket
    }

    /// Spins the thread until the value can be locked.
    ///
    /// The returned value can be used to modify the value,
    /// and will be unlocked after dropping the return value.
    pub fn lock(&self) -> TicketMutexGuard<T> {
        let ticket = self.next_ticket.fetch_add(1, Ordering::Relaxed);

        while self.next_serving.load(Ordering::Acquire) != ticket {
            cpu_relax();
        }

        TicketMutexGuard {
            next_serving: &self.next_serving,
            ticket,
            // Safety
            // We know that we are the next ticket to be served,
            // so there's no other thread accessing the value.
            //
            // Every other thread has another ticket number so it's
            // definitely stuck in the spin loop above.
            value: unsafe { &mut *self.value.get() },
        }
    }

    /// Force unlock the ticket lock, by serving the next ticket.
    ///
    /// # Safety
    ///
    /// This is *extremely* unsafe if the lock is not held by the current
    /// thread. However, this can be useful in some instances for exposing the
    /// lock to FFI that doesn't know how to deal with RAII.
    pub unsafe fn force_unlock(&self) {
        self.next_serving.fetch_add(1, Ordering::Release);
    }

    /// Tries to lock this lock. If it's already locked, `None` is returned,
    /// otherwise a guard that protects the data is returned.
    pub fn try_lock(&self) -> Option<TicketMutexGuard<T>> {
        let ticket = self
            .next_ticket
            .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |ticket| {
                if self.next_serving.load(Ordering::Acquire) == ticket {
                    Some(ticket + 1)
                } else {
                    None
                }
            });

        ticket.ok().map(|ticket| TicketMutexGuard {
            next_serving: &self.next_serving,
            ticket,
            // Safety
            // We have a ticket that is equal to the next_serving ticket, so we know:
            // - that no other thread can have the same ticket id as this thread
            // - that we are the next one to be served so we have exclusive access to the value
            value: unsafe { &mut *self.value.get() },
        })
    }

    /// Returns a mutable reference to the underlying data.
    ///
    /// This will not lock this lock, since this method borrows
    /// this lock mutably so no locking is needed.
    pub fn get_mut(&mut self) -> &mut T {
        // Safety:
        // We know that there are no other references to `self`,
        // so it's safe to return a exclusive reference to the value.
        unsafe { &mut *self.value.get() }
    }
}

impl<T> From<T> for TicketMutex<T> {
    fn from(value: T) -> Self {
        Self::new(value)
    }
}

impl<T: ?Sized + Default> Default for TicketMutex<T> {
    fn default() -> TicketMutex<T> {
        TicketMutex::new(Default::default())
    }
}

impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for TicketMutexGuard<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

impl<'a, T: ?Sized + fmt::Display> fmt::Display for TicketMutexGuard<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl<'a, T: ?Sized> Deref for TicketMutexGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        self.value
    }
}

impl<'a, T: ?Sized> DerefMut for TicketMutexGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        self.value
    }
}

impl<'a, T: ?Sized> Drop for TicketMutexGuard<'a, T> {
    fn drop(&mut self) {
        let new_ticket = self.ticket + 1;
        self.next_serving.store(new_ticket, Ordering::Release);
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::v1::*;

    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::sync::mpsc::channel;
    use std::sync::Arc;
    use std::thread;

    use super::*;

    #[derive(Eq, PartialEq, Debug)]
    struct NonCopy(i32);

    #[test]
    fn smoke() {
        let m = TicketMutex::new(());
        drop(m.lock());
        drop(m.lock());
    }

    #[test]
    fn lots_and_lots() {
        static M: TicketMutex<()> = TicketMutex::new(());
        static mut CNT: u32 = 0;
        const J: u32 = 1000;
        const K: u32 = 3;

        fn inc() {
            for _ in 0..J {
                unsafe {
                    let _g = M.lock();
                    CNT += 1;
                }
            }
        }

        let (tx, rx) = channel();
        for _ in 0..K {
            let tx2 = tx.clone();
            thread::spawn(move || {
                inc();
                tx2.send(()).unwrap();
            });
            let tx2 = tx.clone();
            thread::spawn(move || {
                inc();
                tx2.send(()).unwrap();
            });
        }

        drop(tx);
        for _ in 0..2 * K {
            rx.recv().unwrap();
        }
        assert_eq!(unsafe { CNT }, J * K * 2);
    }

    #[test]
    fn try_lock() {
        let mutex = TicketMutex::new(42);

        // First lock succeeds
        let a = mutex.try_lock();
        assert_eq!(a.as_ref().map(|r| **r), Some(42));

        // Additional lock failes
        let b = mutex.try_lock();
        assert!(b.is_none());

        // After dropping lock, it succeeds again
        ::core::mem::drop(a);
        let c = mutex.try_lock();
        assert_eq!(c.as_ref().map(|r| **r), Some(42));
    }

    #[test]
    fn test_into_inner() {
        let m = TicketMutex::new(NonCopy(10));
        assert_eq!(m.into_inner(), NonCopy(10));
    }

    #[test]
    fn test_into_inner_drop() {
        struct Foo(Arc<AtomicUsize>);
        impl Drop for Foo {
            fn drop(&mut self) {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }
        let num_drops = Arc::new(AtomicUsize::new(0));
        let m = TicketMutex::new(Foo(num_drops.clone()));
        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        {
            let _inner = m.into_inner();
            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        }
        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
    }

    #[test]
    fn test_mutex_arc_nested() {
        // Tests nested mutexes and access
        // to underlying data.
        let arc = Arc::new(TicketMutex::new(1));
        let arc2 = Arc::new(TicketMutex::new(arc));
        let (tx, rx) = channel();
        let _t = thread::spawn(move || {
            let lock = arc2.lock();
            let lock2 = lock.lock();
            assert_eq!(*lock2, 1);
            tx.send(()).unwrap();
        });
        rx.recv().unwrap();
    }

    #[test]
    fn test_mutex_arc_access_in_unwind() {
        let arc = Arc::new(TicketMutex::new(1));
        let arc2 = arc.clone();
        let _ = thread::spawn(move || -> () {
            struct Unwinder {
                i: Arc<TicketMutex<i32>>,
            }
            impl Drop for Unwinder {
                fn drop(&mut self) {
                    *self.i.lock() += 1;
                }
            }
            let _u = Unwinder { i: arc2 };
            panic!();
        })
        .join();
        let lock = arc.lock();
        assert_eq!(*lock, 2);
    }

    #[test]
    fn test_mutex_unsized() {
        let mutex: &TicketMutex<[i32]> = &TicketMutex::new([1, 2, 3]);
        {
            let b = &mut *mutex.lock();
            b[0] = 4;
            b[2] = 5;
        }
        let comp: &[i32] = &[4, 2, 5];
        assert_eq!(&*mutex.lock(), comp);
    }

    #[test]
    fn is_locked() {
        let mutex = TicketMutex::new(());
        assert!(!mutex.is_locked());
        let lock = mutex.lock();
        assert!(mutex.is_locked());
        drop(lock);
        assert!(!mutex.is_locked());
    }
}
<|endoftext|>


<commit_before>use crate::convert::Convert;
use crate::{AHasher};
#[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
use const_random::const_random;
use core::fmt;
use core::hash::BuildHasher;
use core::hash::Hasher;
#[cfg(feature = "std")]
use lazy_static::*;
use core::sync::atomic::{AtomicUsize, Ordering};

#[cfg(feature = "std")]
lazy_static! {
    static ref SEEDS: [u64; 8] = {
        let mut result: [u8; 64] = [0; 64];
        getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
        result.convert()
    };
}
static COUNTER: AtomicUsize = AtomicUsize::new(0);

pub(crate) const PI: [u64;4] = [0x243f_6a88_85a3_08d3, 0x1319_8a2e_0370_7344, 0xA409_3822_299F_31D0, 0x082E_FA98_EC4E_6C89];

/// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create
/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
///
/// [build_hasher]: ahash::
/// [Hasher]: std::hash::Hasher
/// [BuildHasher]: std::hash::BuildHasher
/// [HashMap]: std::collections::HashMap
#[derive(Clone)]
pub struct RandomState {
    pub(crate) k0: u64,
    pub(crate) k1: u64,
    pub(crate) k2: u64,
    pub(crate) k3: u64,
}

impl fmt::Debug for RandomState {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("RandomState { .. }")
    }
}

impl RandomState {
    #[inline]
    #[cfg(feature = "std")]
    pub fn new() -> RandomState {
        let seeds = *SEEDS;
        let mut hasher = AHasher::from_random_state(&RandomState{k0: seeds[0], k1: seeds[1], k2: seeds[2], k3: seeds[3]});
        let stack_mem_loc = &hasher as *const _ as usize;
        hasher.write_usize(COUNTER.fetch_add(stack_mem_loc, Ordering::Relaxed));
        let mix = |k: u64| {
            let mut h = hasher.clone();
            h.write_u64(k);
            h.finish()
        };
        RandomState { k0: mix(seeds[4]), k1: mix(seeds[5]), k2: mix(seeds[6]), k3: mix(seeds[7]) }
    }

    #[inline]
    #[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
    pub fn new() -> RandomState {
        let mut hasher = AHasher::from_random_state(&RandomState::with_fixed_keys());
        let stack_mem_loc = &hasher as *const _ as usize;
        hasher.write_usize(COUNTER.fetch_add(stack_mem_loc, Ordering::Relaxed));
        let mix = |k: u64| {
            let mut h = hasher.clone();
            h.write_u64(k);
            h.finish()
        };
        RandomState { k0: mix(const_random!(u64)), k1: mix(const_random!(u64)), k2: mix(const_random!(u64)), k3: mix(const_random!(u64)) }
    }

    #[inline]
    pub(crate) fn with_fixed_keys() -> RandomState {
        #[cfg(feature = "std")]
        {
            let seeds = *SEEDS;
            RandomState { k0: seeds[4], k1: seeds[5], k2: seeds[6], k3: seeds[7] }
        }
        #[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
        {
            RandomState { k0: const_random!(u64), k1: const_random!(u64), k2: const_random!(u64), k3: const_random!(u64) }
        }
        #[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
        {
            RandomState { k0: PI[3], k1: PI[2], k2: PI[1], k3: PI[0] }
        }
    }

    /// Allows for explicitly setting the seeds to used.
    pub const fn with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        RandomState { k0, k1, k2, k3 }
    }
}

#[cfg(any(feature = "std", feature = "compile-time-rng"))]
impl Default for RandomState {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl BuildHasher for RandomState {
    type Hasher = AHasher;

    /// Constructs a new [AHasher] with keys based on this [RandomState] object.
    /// This means that two different [RandomState]s will will generate
    /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
    /// will generate the same hashes for the same input data.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::{AHasher, RandomState};
    /// use std::hash::{Hasher, BuildHasher};
    ///
    /// let build_hasher = RandomState::new();
    /// let mut hasher_1 = build_hasher.build_hasher();
    /// let mut hasher_2 = build_hasher.build_hasher();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    ///
    /// let other_build_hasher = RandomState::new();
    /// let mut different_hasher = other_build_hasher.build_hasher();
    /// different_hasher.write_u32(1234);
    /// assert_ne!(different_hasher.finish(), hasher_1.finish());
    /// ```
    /// [Hasher]: std::hash::Hasher
    /// [BuildHasher]: std::hash::BuildHasher
    /// [HashMap]: std::collections::HashMap
    #[inline]
    fn build_hasher(&self) -> AHasher {
        AHasher::from_random_state(self)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[cfg(feature = "std")]
    #[test]
    fn test_unique() {
        let a = RandomState::new();
        let b = RandomState::new();
        assert_ne!(a.build_hasher().finish(), b.build_hasher().finish());
    }

    #[test]
    fn test_with_seeds_const() {
        const _CONST_RANDOM_STATE: RandomState = RandomState::with_seeds(17, 19, 21, 23);
    }
}
<commit_msg>Add RandomState::new without any features<commit_after>use crate::convert::Convert;
use crate::{AHasher};
#[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
use const_random::const_random;
use core::fmt;
use core::hash::BuildHasher;
use core::hash::Hasher;
#[cfg(feature = "std")]
use lazy_static::*;
use core::sync::atomic::{AtomicUsize, Ordering};

#[cfg(feature = "std")]
lazy_static! {
    static ref SEEDS: [u64; 8] = {
        let mut result: [u8; 64] = [0; 64];
        getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
        result.convert()
    };
}
static COUNTER: AtomicUsize = AtomicUsize::new(0);

pub(crate) const PI: [u64;4] = [0x243f_6a88_85a3_08d3, 0x1319_8a2e_0370_7344, 0xA409_3822_299F_31D0, 0x082E_FA98_EC4E_6C89];

/// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create
/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
///
/// [build_hasher]: ahash::
/// [Hasher]: std::hash::Hasher
/// [BuildHasher]: std::hash::BuildHasher
/// [HashMap]: std::collections::HashMap
#[derive(Clone)]
pub struct RandomState {
    pub(crate) k0: u64,
    pub(crate) k1: u64,
    pub(crate) k2: u64,
    pub(crate) k3: u64,
}

impl fmt::Debug for RandomState {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("RandomState { .. }")
    }
}

impl RandomState {
    #[inline]
    fn generate_with(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        let mut hasher = AHasher::from_random_state(&RandomState::with_fixed_keys());
        let stack_mem_loc = &hasher as *const _ as usize;
        hasher.write_usize(COUNTER.fetch_add(stack_mem_loc, Ordering::Relaxed));
        let mix = |k: u64| {
            let mut h = hasher.clone();
            h.write_u64(k);
            h.finish()
        };

        RandomState { k0: mix(k0), k1: mix(k1), k2: mix(k2), k3: mix(k3) }
    }

    #[inline]
    pub fn new() -> RandomState {
        #[cfg(feature = "std")]
        {
            RandomState::generate_with(SEEDS[0], SEEDS[1], SEEDS[2], SEEDS[3])
        }

        #[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
        {
            RandomState::generate_with(const_random!(u64), const_random!(u64), const_random!(u64), const_random!(u64))
        }

        #[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
        {
            RandomState::generate_with(PI[0], PI[1], PI[2], PI[3])
        }
    }

    #[inline]
    pub(crate) fn with_fixed_keys() -> RandomState {
        #[cfg(feature = "std")]
        {
            RandomState { k0: SEEDS[4], k1: SEEDS[5], k2: SEEDS[6], k3: SEEDS[7] }
        }
        #[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
        {
            RandomState { k0: const_random!(u64), k1: const_random!(u64), k2: const_random!(u64), k3: const_random!(u64) }
        }
        #[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
        {
            RandomState { k0: PI[3], k1: PI[2], k2: PI[1], k3: PI[0] }
        }
    }

    /// Allows for explicitly setting the seeds to used.
    pub const fn with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        RandomState { k0, k1, k2, k3 }
    }
}

#[cfg(any(feature = "std", feature = "compile-time-rng"))]
impl Default for RandomState {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl BuildHasher for RandomState {
    type Hasher = AHasher;

    /// Constructs a new [AHasher] with keys based on this [RandomState] object.
    /// This means that two different [RandomState]s will will generate
    /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
    /// will generate the same hashes for the same input data.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::{AHasher, RandomState};
    /// use std::hash::{Hasher, BuildHasher};
    ///
    /// let build_hasher = RandomState::new();
    /// let mut hasher_1 = build_hasher.build_hasher();
    /// let mut hasher_2 = build_hasher.build_hasher();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    ///
    /// let other_build_hasher = RandomState::new();
    /// let mut different_hasher = other_build_hasher.build_hasher();
    /// different_hasher.write_u32(1234);
    /// assert_ne!(different_hasher.finish(), hasher_1.finish());
    /// ```
    /// [Hasher]: std::hash::Hasher
    /// [BuildHasher]: std::hash::BuildHasher
    /// [HashMap]: std::collections::HashMap
    #[inline]
    fn build_hasher(&self) -> AHasher {
        AHasher::from_random_state(self)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_unique() {
        let a = RandomState::new();
        let b = RandomState::new();
        assert_ne!(a.build_hasher().finish(), b.build_hasher().finish());
    }

    #[test]
    fn test_with_seeds_const() {
        const _CONST_RANDOM_STATE: RandomState = RandomState::with_seeds(17, 19, 21, 23);
    }
}
<|endoftext|>


<commit_before>use hdr_histogram::simple_hdr_histogram::*;

#[test]
fn count_at_value_on_empty() {
    let h = init_histo(1, 100000, 3);

    assert_eq!(h.get_count_at_value(1).unwrap(), 0);
    assert_eq!(h.get_count_at_value(5000).unwrap(), 0);
    assert_eq!(h.get_count_at_value(100000).unwrap(), 0);
}

#[test]
fn count_at_value_after_record() {
    let mut h = init_histo(1, 100000, 3);

    h.record_single_value(5000).unwrap();

    assert_eq!(h.get_count_at_value(1).unwrap(), 0);
    assert_eq!(h.get_count_at_value(5000).unwrap(), 1);
    assert_eq!(h.get_count_at_value(100000).unwrap(), 0);
}

#[test]
fn can_get_count_after_record() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();

    let count = h.get_count();
    assert_eq!(count, 1);
}

#[test]
fn can_get_max_after_record() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();

    let max = h.get_max();
    assert_eq!(max, 5000);
}

#[test]
fn can_record_single_value() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();
}

#[test]
fn can_compute_indexes_for_smallest_value() {
    let h = init_histo(1, 100000, 3);
    let value = 1;
    assert_eq!(h.get_bucket_index(value), 0);
    assert_eq!(h.get_sub_bucket_index(value, 0), 1);
    assert_eq!(h.counts_array_index(value), 1);
}

#[test]
fn can_compute_counts_array_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.counts_array_index(5000);

    assert_eq!(result, 3298);
}

#[test]
fn can_get_bucket_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.get_bucket_index(5000);
    assert_eq!(result, 2)
}

#[test]
fn can_get_sub_bucket_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.get_sub_bucket_index(5000, 2);
    assert_eq!(result, 1250)
}

#[test]
fn sub_bucket_count_medium_precision() {
    let h = init_histo(1, 100000, 3);

    assert_eq!(2048_usize, h.sub_bucket_count);
    assert_eq!(1024_usize, h.sub_bucket_half_count);
    assert_eq!(10, h.sub_bucket_half_count_magnitude);
    assert_eq!(2047, h.sub_bucket_mask);
}

#[test]
fn sub_bucket_count_min_precision() {
    let h = init_histo(1, 100000, 0);

    assert_eq!(2_usize, h.sub_bucket_count);
    assert_eq!(1_usize, h.sub_bucket_half_count);
    assert_eq!(0, h.sub_bucket_half_count_magnitude);
    assert_eq!(1, h.sub_bucket_mask);
}

#[test]
fn sub_bucket_count_max_precision() {
    let h = init_histo(1, 100000, 5);

    assert_eq!(262144_usize, h.sub_bucket_count);
    assert_eq!(131072usize, h.sub_bucket_half_count);
    assert_eq!(17, h.sub_bucket_half_count_magnitude);
    assert_eq!(262143, h.sub_bucket_mask);
}

/// lowest_discernible_value: must be >= 1
/// highest_trackable_value: must be >= 2 * lowest_discernible_value
/// num_significant_digits: must be <= 5
fn init_histo(lowest_discernible_value: u64, highest_trackable_value: u64, num_significant_digits: u32) -> SimpleHdrHistogram<u64> {

    assert!(lowest_discernible_value >= 1);
    assert!(highest_trackable_value >= 2 * lowest_discernible_value);
    assert!(num_significant_digits <= 5);

    let largest_value_with_single_unit_resolution = 2_u64 * 10_u64.pow(num_significant_digits);

    let unit_magnitude = ((lowest_discernible_value as f64).ln() / 2_f64.ln()) as u32;
    let unit_magnitude_mask: u64  = (1_u64 << unit_magnitude) - 1;

    // find nearest power of 2 to largest_value_with_single_unit_resolution
    let sub_bucket_count_magnitude: u32 =
    ((largest_value_with_single_unit_resolution as f64).ln() / 2_f64.ln()).ceil() as u32;

    // ugly looking... how should ternaries be done?
    let sub_bucket_half_count_magnitude: u32 = (if sub_bucket_count_magnitude > 1 { sub_bucket_count_magnitude } else { 1 }) - 1;
    let sub_bucket_count: usize = 2_usize.pow(sub_bucket_half_count_magnitude + 1);
    let sub_bucket_half_count: usize = sub_bucket_count / 2;
    // TODO is this cast OK?
    let sub_bucket_mask = ((sub_bucket_count - 1) << unit_magnitude) as u64;

    let counts_arr_len = counts_arr_len(highest_trackable_value, sub_bucket_count, unit_magnitude);
    let bucket_count = buckets_needed_for_value(highest_trackable_value, sub_bucket_count, unit_magnitude);

    let leading_zero_count_base: usize = (64_u32 - unit_magnitude - sub_bucket_half_count_magnitude - 1) as usize;

    SimpleHdrHistogram {
        leading_zeros_count_base: leading_zero_count_base,
        unit_magnitude: unit_magnitude,
        sub_bucket_mask: sub_bucket_mask,
        sub_bucket_count: sub_bucket_count,
        sub_bucket_half_count: sub_bucket_half_count,
        sub_bucket_half_count_magnitude: sub_bucket_half_count_magnitude,
        counts: vec![0; counts_arr_len],
        counts_array_length: counts_arr_len,
        normalizing_index_offset: 0_usize, // 0 for normal Histogram ctor in Java impl
        min_non_zero_value: u64::max_value(),
        total_count: 0,
        max_value: 0,
        unit_magnitude_mask: unit_magnitude_mask
    }
}

fn buckets_needed_for_value(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {

    // TODO is this cast ok?
    let mut smallest_untrackable_value: u64 = (sub_bucket_count << unit_magnitude) as u64;
    let mut buckets_needed: usize = 1;

    while smallest_untrackable_value <= value {
        if smallest_untrackable_value > u64::max_value() / 2 {
            return buckets_needed + 1;
        }

        smallest_untrackable_value = smallest_untrackable_value << 1;
        buckets_needed += 1;
    }

    return buckets_needed;
}

fn counts_arr_len_for_buckets(buckets: usize, sub_bucket_count: usize) -> usize {
    (buckets + 1) * (sub_bucket_count / 2)
}

fn counts_arr_len(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {
    counts_arr_len_for_buckets(buckets_needed_for_value(value, sub_bucket_count, unit_magnitude), sub_bucket_count)
}<commit_msg>rust docs on testing use assert_eq!(expected, actual) so switching to that<commit_after>use hdr_histogram::simple_hdr_histogram::*;

#[test]
fn count_at_value_on_empty() {
    let h = init_histo(1, 100000, 3);

    assert_eq!(0, h.get_count_at_value(1).unwrap());
    assert_eq!(0, h.get_count_at_value(5000).unwrap());
    assert_eq!(0, h.get_count_at_value(100000).unwrap());
}

#[test]
fn count_at_value_after_record() {
    let mut h = init_histo(1, 100000, 3);

    h.record_single_value(5000).unwrap();

    assert_eq!(0, h.get_count_at_value(1).unwrap());
    assert_eq!(1, h.get_count_at_value(5000).unwrap());
    assert_eq!(0, h.get_count_at_value(100000).unwrap());
}

#[test]
fn can_get_count_after_record() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();

    let count = h.get_count();
    assert_eq!(1, count);
}

#[test]
fn can_get_max_after_record() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();

    let max = h.get_max();
    assert_eq!(5000, max);
}

#[test]
fn can_record_single_value() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();
}

#[test]
fn can_compute_indexes_for_smallest_value() {
    let h = init_histo(1, 100000, 3);
    let value = 1;
    assert_eq!(0, h.get_bucket_index(value));
    assert_eq!(1, h.get_sub_bucket_index(value, 0));
    assert_eq!(1, h.counts_array_index(value));
}

#[test]
fn can_compute_counts_array_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.counts_array_index(5000);

    assert_eq!(3298, result);
}

#[test]
fn can_get_bucket_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.get_bucket_index(5000);
    assert_eq!(2, result)
}

#[test]
fn can_get_sub_bucket_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.get_sub_bucket_index(5000, 2);
    assert_eq!(1250, result)
}

#[test]
fn sub_bucket_count_medium_precision() {
    let h = init_histo(1, 100000, 3);

    assert_eq!(2048_usize, h.sub_bucket_count);
    assert_eq!(1024_usize, h.sub_bucket_half_count);
    assert_eq!(10, h.sub_bucket_half_count_magnitude);
    assert_eq!(2047, h.sub_bucket_mask);
}

#[test]
fn sub_bucket_count_min_precision() {
    let h = init_histo(1, 100000, 0);

    assert_eq!(2_usize, h.sub_bucket_count);
    assert_eq!(1_usize, h.sub_bucket_half_count);
    assert_eq!(0, h.sub_bucket_half_count_magnitude);
    assert_eq!(1, h.sub_bucket_mask);
}

#[test]
fn sub_bucket_count_max_precision() {
    let h = init_histo(1, 100000, 5);

    assert_eq!(262144_usize, h.sub_bucket_count);
    assert_eq!(131072usize, h.sub_bucket_half_count);
    assert_eq!(17, h.sub_bucket_half_count_magnitude);
    assert_eq!(262143, h.sub_bucket_mask);
}

/// lowest_discernible_value: must be >= 1
/// highest_trackable_value: must be >= 2 * lowest_discernible_value
/// num_significant_digits: must be <= 5
fn init_histo(lowest_discernible_value: u64, highest_trackable_value: u64, num_significant_digits: u32) -> SimpleHdrHistogram<u64> {

    assert!(lowest_discernible_value >= 1);
    assert!(highest_trackable_value >= 2 * lowest_discernible_value);
    assert!(num_significant_digits <= 5);

    let largest_value_with_single_unit_resolution = 2_u64 * 10_u64.pow(num_significant_digits);

    let unit_magnitude = ((lowest_discernible_value as f64).ln() / 2_f64.ln()) as u32;
    let unit_magnitude_mask: u64  = (1_u64 << unit_magnitude) - 1;

    // find nearest power of 2 to largest_value_with_single_unit_resolution
    let sub_bucket_count_magnitude: u32 =
    ((largest_value_with_single_unit_resolution as f64).ln() / 2_f64.ln()).ceil() as u32;

    // ugly looking... how should ternaries be done?
    let sub_bucket_half_count_magnitude: u32 = (if sub_bucket_count_magnitude > 1 { sub_bucket_count_magnitude } else { 1 }) - 1;
    let sub_bucket_count: usize = 2_usize.pow(sub_bucket_half_count_magnitude + 1);
    let sub_bucket_half_count: usize = sub_bucket_count / 2;
    // TODO is this cast OK?
    let sub_bucket_mask = ((sub_bucket_count - 1) << unit_magnitude) as u64;

    let counts_arr_len = counts_arr_len(highest_trackable_value, sub_bucket_count, unit_magnitude);
    let bucket_count = buckets_needed_for_value(highest_trackable_value, sub_bucket_count, unit_magnitude);

    let leading_zero_count_base: usize = (64_u32 - unit_magnitude - sub_bucket_half_count_magnitude - 1) as usize;

    SimpleHdrHistogram {
        leading_zeros_count_base: leading_zero_count_base,
        unit_magnitude: unit_magnitude,
        sub_bucket_mask: sub_bucket_mask,
        sub_bucket_count: sub_bucket_count,
        sub_bucket_half_count: sub_bucket_half_count,
        sub_bucket_half_count_magnitude: sub_bucket_half_count_magnitude,
        counts: vec![0; counts_arr_len],
        counts_array_length: counts_arr_len,
        normalizing_index_offset: 0_usize, // 0 for normal Histogram ctor in Java impl
        min_non_zero_value: u64::max_value(),
        total_count: 0,
        max_value: 0,
        unit_magnitude_mask: unit_magnitude_mask
    }
}

fn buckets_needed_for_value(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {

    // TODO is this cast ok?
    let mut smallest_untrackable_value: u64 = (sub_bucket_count << unit_magnitude) as u64;
    let mut buckets_needed: usize = 1;

    while smallest_untrackable_value <= value {
        if smallest_untrackable_value > u64::max_value() / 2 {
            return buckets_needed + 1;
        }

        smallest_untrackable_value = smallest_untrackable_value << 1;
        buckets_needed += 1;
    }

    return buckets_needed;
}

fn counts_arr_len_for_buckets(buckets: usize, sub_bucket_count: usize) -> usize {
    (buckets + 1) * (sub_bucket_count / 2)
}

fn counts_arr_len(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {
    counts_arr_len_for_buckets(buckets_needed_for_value(value, sub_bucket_count, unit_magnitude), sub_bucket_count)
}<|endoftext|>


<commit_before>use russell_lab::{Matrix, Vector};

/// Defines a tetrahedron with 10 nodes (quadratic faces)
///
/// # Local IDs of nodes
///
/// ```text
///               t               r    s    t
///               |         p:0 [0.0, 0.0, 0.0]
///               @ 3       p:1 [1.0, 0.0, 0.0]
///              /|`.       p:2 [0.0, 1.0, 0.0]
///              ||  `,     p:3 [0.0, 0.0, 1.0]
///             / |    ',
///             | |      \
///            /  |       `.
///            |  |         `,  9
///           /   @ 7         @,
///           |   |             \
///          /    |              `.
///        8 @    |                ',
///         /     |                  \
///         |     @.,,_               `.
///        |     / 0   ``'-.,@__        `.
///        |    /           6  ``''-.,,_  ',
///       |    /                        ``-@-,_s
///       |  @'                       ,.-`` 2
///      |  , 4                  _,-'`
///      ' /            5    ,.'`
///     | /             _@-``      r    s    t
///     '/          ,-'`     p:4 [0.5, 0.0, 0.0]
///    |/      ,.-``         p:5 [0.5, 0.5, 0.0]
///    /  _,-``              p:6 [0.0, 0.5, 0.0]
///   @ '`                   p:7 [0.0, 0.0, 0.5]
///  / 1                     p:8 [0.5, 0.0, 0.5]
/// r                        p:9 [0.0, 0.5, 0.5]
/// ```
///
/// # Local IDs of edges
///
/// The order of edge nodes corresponds to Lin2 nodes.
///
/// ```text
///               t                    p0  p1 p2
///               |                e:0 [0, 1, 4]
///               3                e:1 [1, 2, 5]
///              /|`.              e:2 [2, 0, 6]
///              ||  `,            e:3 [0, 3, 7]
///             / |    ',          e:4 [1, 3, 8]
///             | |      \         e:5 [2, 3, 9]
///            /  |       `.
///            |  |         `,
///           /   7(3)        `9(5)
///           |   |             \
///          /    |              `.
///       (4)8    |                ',
///         /     |                  \
///         |     0.,,_               `.
///        |     /     ``'-.,6__        `.
///        |    /          (2) ``''-.,,_  ',
///       |    /                        ``'2-,_s
///       |  4'                       ,.-``
///      |  ,(0)                 _,-'`
///      ' /                 ,.'`
///     | /             _5-``
///     '/          ,-'` (1)
///    |/      ,.-``
///    /  _,-``
///   1,'`
///  /
/// r
/// ```
///
/// # Local IDs of faces
///
/// ```text
///               t           p0 p1 p2 p3 p4 p5
///               |       f:0 [0, 3, 2, 7, 9, 6]
///               3       f:1 [0, 1, 3, 4, 8, 7]
///              /|`.     f:2 [0, 2, 1, 6, 5, 4]
///              ||  `,   f:3 [1, 2, 3, 5, 9, 8]
///             / |    ',
///             | |      \
///            /  |       `.
///            |  |         `,
///           /   7           `9
///           |   |     [0]     \
///          /    |              `.
///          8    |                ',
///         / [1] |    ,             \
///         |     0. ,' \             `.
///        |     /   \ 3 \ .,6__        `.
///        |    /     \ ,'     ``''-.,,_  ',
///       |    /       '                ``'2-,_s
///       |  4'                       ,.-``
///      |  ,      [2]           _,-'`
///      ' /                 ,.'`
///     | /             _5-``
///     '/          ,-'`
///    |/      ,.-``
///    /  _,-``
///   1,'`
///  /
/// r
/// ```
///
/// # Note about face nodes
///
/// * The order of face nodes is such that the normals are outward
/// * The order of face nodes corresponds to **Tri6** nodes
pub struct Tet10 {}

impl Tet10 {
    pub const GEO_NDIM: usize = 3;
    pub const NNODE: usize = 10;
    pub const NEDGE: usize = 6;
    pub const NFACE: usize = 4;
    pub const EDGE_NNODE: usize = 3;
    pub const FACE_NNODE: usize = 6;
    pub const FACE_NEDGE: usize = 3;

    #[rustfmt::skip]
    pub const EDGE_NODE_IDS: [[usize; Tet10::EDGE_NNODE]; Tet10::NEDGE] = [
        [0, 1, 4],
        [1, 2, 5],
        [2, 0, 6],
        [0, 3, 7],
        [1, 3, 8],
        [2, 3, 9],
    ];

    #[rustfmt::skip]
    pub const FACE_NODE_IDS: [[usize; Tet10::FACE_NNODE]; Tet10::NFACE] = [
        [0, 3, 2, 7, 9, 6],
        [0, 1, 3, 4, 8, 7],
        [0, 2, 1, 6, 5, 4],
        [1, 2, 3, 5, 9, 8],
    ];

    #[rustfmt::skip]
    pub const FACE_EDGE_NODE_IDS: [[[usize; Tet10::EDGE_NNODE]; Tet10::FACE_NEDGE]; Tet10::NFACE] = [
        [[0, 3, 7], [3, 2, 9], [2, 0, 6]],
        [[0, 1, 4], [1, 3, 8], [3, 0, 7]],
        [[0, 2, 6], [2, 1, 5], [1, 0, 4]],
        [[1, 2, 5], [2, 3, 9], [3, 1, 8]],
    ];

    #[rustfmt::skip]
    pub const NODE_REFERENCE_COORDS: [[f64; Tet10::GEO_NDIM]; Tet10::NNODE] = [
        [0.0, 0.0, 0.0], // 0
        [1.0, 0.0, 0.0], // 1
        [0.0, 1.0, 0.0], // 2
        [0.0, 0.0, 1.0], // 3
        [0.5, 0.0, 0.0], // 4
        [0.5, 0.5, 0.0], // 5
        [0.0, 0.5, 0.0], // 6
        [0.0, 0.0, 0.5], // 7
        [0.5, 0.0, 0.5], // 8
        [0.0, 0.5, 0.5], // 9
    ];

    /// Computes the interpolation functions
    pub fn calc_interp(interp: &mut Vector, ksi: &[f64]) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        let u = 1.0 - r - s - t;

        interp[0] = u * (2.0 * u - 1.0);
        interp[1] = r * (2.0 * r - 1.0);
        interp[2] = s * (2.0 * s - 1.0);
        interp[3] = t * (2.0 * t - 1.0);
        interp[4] = 4.0 * u * r;
        interp[5] = 4.0 * r * s;
        interp[6] = 4.0 * s * u;
        interp[7] = 4.0 * u * t;
        interp[8] = 4.0 * r * t;
        interp[9] = 4.0 * s * t;
    }

    /// Computes the derivatives of interpolation functions
    pub fn calc_deriv(deriv: &mut Matrix, ksi: &[f64]) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        deriv[0][0] = 4.0 * (r + s + t) - 3.0;
        deriv[1][0] = 4.0 * r - 1.0;
        deriv[2][0] = 0.0;
        deriv[3][0] = 0.0;
        deriv[4][0] = 4.0 - 8.0 * r - 4.0 * s - 4.0 * t;
        deriv[5][0] = 4.0 * s;
        deriv[6][0] = -4.0 * s;
        deriv[7][0] = -4.0 * t;
        deriv[8][0] = 4.0 * t;
        deriv[9][0] = 0.0;

        deriv[0][1] = 4.0 * (r + s + t) - 3.0;
        deriv[1][1] = 0.0;
        deriv[2][1] = 4.0 * s - 1.0;
        deriv[3][1] = 0.0;
        deriv[4][1] = -4.0 * r;
        deriv[5][1] = 4.0 * r;
        deriv[6][1] = 4.0 - 4.0 * r - 8.0 * s - 4.0 * t;
        deriv[7][1] = -4.0 * t;
        deriv[8][1] = 0.0;
        deriv[9][1] = 4.0 * t;

        deriv[0][2] = 4.0 * (r + s + t) - 3.0;
        deriv[1][2] = 0.0;
        deriv[2][2] = 0.0;
        deriv[3][2] = 4.0 * t - 1.0;
        deriv[4][2] = -4.0 * r;
        deriv[5][2] = 0.0;
        deriv[6][2] = -4.0 * s;
        deriv[7][2] = 4.0 - 4.0 * r - 4.0 * s - 8.0 * t;
        deriv[8][2] = 4.0 * r;
        deriv[9][2] = 4.0 * s;
    }
}
<commit_msg>Improve Tet10 comments<commit_after>use russell_lab::{Matrix, Vector};

/// Defines a tetrahedron with 10 nodes (quadratic faces)
///
/// # Local IDs of nodes
///
/// ```text
///               t               r    s    t
///               |         p:0 [0.0, 0.0, 0.0]
///               3         p:1 [1.0, 0.0, 0.0]
///              /|`.       p:2 [0.0, 1.0, 0.0]
///              ||  `,     p:3 [0.0, 0.0, 1.0]
///             / |    ',
///             | |      \
///            /  |       `.
///            |  |         `,
///           /   7           9,
///           |   |             \
///          /    |              `.
///          8    |                ',
///         /     |                  \
///         |     0.,,_               `.
///        |     /     ``'-.,6__        `.
///        |    /              ``''-.,,_  ',
///       |    /                        ``-2-,_s
///       |  4'                       ,.-`` 2
///      |  ,                    _,-'`
///      ' /                 ,.'`
///     | /             _5-``      r    s    t
///     '/          ,-'`     p:4 [0.5, 0.0, 0.0]
///    |/      ,.-``         p:5 [0.5, 0.5, 0.0]
///    /  _,-``              p:6 [0.0, 0.5, 0.0]
///   1 '`                   p:7 [0.0, 0.0, 0.5]
///  /                       p:8 [0.5, 0.0, 0.5]
/// r                        p:9 [0.0, 0.5, 0.5]
/// ```
///
/// # Local IDs of edges
///
/// The order of edge nodes corresponds to Lin3 nodes.
///
/// ```text
///               t                    p0  p1 p2
///               |                e:0 [0, 1, 4]
///               3                e:1 [1, 2, 5]
///              /|`.              e:2 [2, 0, 6]
///              ||  `,            e:3 [0, 3, 7]
///             / |    ',          e:4 [1, 3, 8]
///             | |      \         e:5 [2, 3, 9]
///            /  |       `.
///            |  |         `,
///           /   7(3)        `9(5)
///           |   |             \
///          /    |              `.
///       (4)8    |                ',
///         /     |                  \
///         |     0.,,_               `.
///        |     /     ``'-.,6__        `.
///        |    /          (2) ``''-.,,_  ',
///       |    /                        ``'2-,_s
///       |  4'                       ,.-``
///      |  ,(0)                 _,-'`
///      ' /                 ,.'`
///     | /             _5-``
///     '/          ,-'` (1)
///    |/      ,.-``
///    /  _,-``
///   1,'`
///  /
/// r
/// ```
///
/// # Local IDs of faces
///
/// ```text
///               t           p0 p1 p2 p3 p4 p5
///               |       f:0 [0, 3, 2, 7, 9, 6]
///               3       f:1 [0, 1, 3, 4, 8, 7]
///              /|`.     f:2 [0, 2, 1, 6, 5, 4]
///              ||  `,   f:3 [1, 2, 3, 5, 9, 8]
///             / |    ',
///             | |      \
///            /  |       `.
///            |  |         `,
///           /   7           `9
///           |   |     [0]     \
///          /    |              `.
///          8    |                ',
///         / [1] |    ,             \
///         |     0. ,' \             `.
///        |     /   \ 3 \ .,6__        `.
///        |    /     \ ,'     ``''-.,,_  ',
///       |    /       '                ``'2-,_s
///       |  4'                       ,.-``
///      |  ,      [2]           _,-'`
///      ' /                 ,.'`
///     | /             _5-``
///     '/          ,-'`
///    |/      ,.-``
///    /  _,-``
///   1,'`
///  /
/// r
/// ```
///
/// # Note about face nodes
///
/// * The order of face nodes is such that the normals are outward
/// * The order of face nodes corresponds to **Tri6** nodes
pub struct Tet10 {}

impl Tet10 {
    pub const GEO_NDIM: usize = 3;
    pub const NNODE: usize = 10;
    pub const NEDGE: usize = 6;
    pub const NFACE: usize = 4;
    pub const EDGE_NNODE: usize = 3;
    pub const FACE_NNODE: usize = 6;
    pub const FACE_NEDGE: usize = 3;

    #[rustfmt::skip]
    pub const EDGE_NODE_IDS: [[usize; Tet10::EDGE_NNODE]; Tet10::NEDGE] = [
        [0, 1, 4],
        [1, 2, 5],
        [2, 0, 6],
        [0, 3, 7],
        [1, 3, 8],
        [2, 3, 9],
    ];

    #[rustfmt::skip]
    pub const FACE_NODE_IDS: [[usize; Tet10::FACE_NNODE]; Tet10::NFACE] = [
        [0, 3, 2, 7, 9, 6],
        [0, 1, 3, 4, 8, 7],
        [0, 2, 1, 6, 5, 4],
        [1, 2, 3, 5, 9, 8],
    ];

    #[rustfmt::skip]
    pub const FACE_EDGE_NODE_IDS: [[[usize; Tet10::EDGE_NNODE]; Tet10::FACE_NEDGE]; Tet10::NFACE] = [
        [[0, 3, 7], [3, 2, 9], [2, 0, 6]],
        [[0, 1, 4], [1, 3, 8], [3, 0, 7]],
        [[0, 2, 6], [2, 1, 5], [1, 0, 4]],
        [[1, 2, 5], [2, 3, 9], [3, 1, 8]],
    ];

    #[rustfmt::skip]
    pub const NODE_REFERENCE_COORDS: [[f64; Tet10::GEO_NDIM]; Tet10::NNODE] = [
        [0.0, 0.0, 0.0], // 0
        [1.0, 0.0, 0.0], // 1
        [0.0, 1.0, 0.0], // 2
        [0.0, 0.0, 1.0], // 3
        [0.5, 0.0, 0.0], // 4
        [0.5, 0.5, 0.0], // 5
        [0.0, 0.5, 0.0], // 6
        [0.0, 0.0, 0.5], // 7
        [0.5, 0.0, 0.5], // 8
        [0.0, 0.5, 0.5], // 9
    ];

    /// Computes the interpolation functions
    pub fn calc_interp(interp: &mut Vector, ksi: &[f64]) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        let u = 1.0 - r - s - t;

        interp[0] = u * (2.0 * u - 1.0);
        interp[1] = r * (2.0 * r - 1.0);
        interp[2] = s * (2.0 * s - 1.0);
        interp[3] = t * (2.0 * t - 1.0);
        interp[4] = 4.0 * u * r;
        interp[5] = 4.0 * r * s;
        interp[6] = 4.0 * s * u;
        interp[7] = 4.0 * u * t;
        interp[8] = 4.0 * r * t;
        interp[9] = 4.0 * s * t;
    }

    /// Computes the derivatives of interpolation functions
    pub fn calc_deriv(deriv: &mut Matrix, ksi: &[f64]) {
        let (r, s, t) = (ksi[0], ksi[1], ksi[2]);

        deriv[0][0] = 4.0 * (r + s + t) - 3.0;
        deriv[1][0] = 4.0 * r - 1.0;
        deriv[2][0] = 0.0;
        deriv[3][0] = 0.0;
        deriv[4][0] = 4.0 - 8.0 * r - 4.0 * s - 4.0 * t;
        deriv[5][0] = 4.0 * s;
        deriv[6][0] = -4.0 * s;
        deriv[7][0] = -4.0 * t;
        deriv[8][0] = 4.0 * t;
        deriv[9][0] = 0.0;

        deriv[0][1] = 4.0 * (r + s + t) - 3.0;
        deriv[1][1] = 0.0;
        deriv[2][1] = 4.0 * s - 1.0;
        deriv[3][1] = 0.0;
        deriv[4][1] = -4.0 * r;
        deriv[5][1] = 4.0 * r;
        deriv[6][1] = 4.0 - 4.0 * r - 8.0 * s - 4.0 * t;
        deriv[7][1] = -4.0 * t;
        deriv[8][1] = 0.0;
        deriv[9][1] = 4.0 * t;

        deriv[0][2] = 4.0 * (r + s + t) - 3.0;
        deriv[1][2] = 0.0;
        deriv[2][2] = 0.0;
        deriv[3][2] = 4.0 * t - 1.0;
        deriv[4][2] = -4.0 * r;
        deriv[5][2] = 0.0;
        deriv[6][2] = -4.0 * s;
        deriv[7][2] = 4.0 - 4.0 * r - 4.0 * s - 8.0 * t;
        deriv[8][2] = 4.0 * r;
        deriv[9][2] = 4.0 * s;
    }
}
<|endoftext|>


<commit_before>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;
use std::fmt::Debug;
use std::cmp::PartialEq;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

fn test_parse<T: Debug + PartialEq>(source: &str, func: &Fn(&mut ParseIter) -> T, expect: T) {
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(func(&mut it), expect);

  // wait, why do these all use parse_un_expr instead of the &Fn we get?
  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();

  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();

  assert_eq!(parse_un_expr(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_quark() {
  test_parse("null", &parse_quark, Ok(Node::Null));
  test_parse("true", &parse_quark, Ok(Node::Bool(true)));
  test_parse("false", &parse_quark, Ok(Node::Bool(false)));
  test_parse("1.3", &parse_quark, Ok(Node::Float(1.3)));
  test_parse("0.3", &parse_quark, Ok(Node::Float(0.3)));
  test_parse("2", &parse_quark, Ok(Node::Int(2)));
  test_parse("3", &parse_quark, Ok(Node::Int(3)));
  test_parse("name", &parse_quark, Ok(Node::Name(String::from("name"))));
  test_parse("table", &parse_quark, Ok(Node::Table));
}

#[test]
fn test_atom() {
  test_parse("null", &parse_atom, Ok(Node::Null));

  test_parse("(null)", &parse_atom, Ok(Node::Null));
}

#[test]
fn test_simple() {
  test_parse("foo", &parse_simple, Ok(Node::Name(String::from("foo"))));
  test_parse(
    "foo.bar",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    }),
  );
  test_parse(
    "foo[bar]",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Name(String::from("bar"))),
    }),
  );
  test_parse(
    "foo()",
    &parse_simple,
    Ok(Node::Call {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo:bar()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Name(String::from("foo"))),
      method: Box::new(Node::Str(String::from("bar"))),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo.bar()",
    &parse_simple,
    Ok(Node::Call {
      func: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo.bar[baz]:qux()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Index {
        lhs: Box::new(Node::Index {
          lhs: Box::new(Node::Name(String::from("foo"))),
          rhs: Box::new(Node::Str(String::from("bar"))),
        }),
        rhs: Box::new(Node::Name(String::from("baz"))),
      }),
      method: Box::new(Node::Str(String::from("qux"))),
      args: Vec::new(),
    }),
  );
}

#[test]
fn test_fn_args() {
  test_parse("()", &parse_fn_args, Ok(Vec::new()));
}

#[test]
fn test_un_expr() {
  test_parse("5", &parse_un_expr, Ok(Node::Int(5)));

  test_parse(
    "foo()",
    &parse_un_expr,
    Ok(Node::Call {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    }),
  );

  test_parse(
    "-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "-foo.bar",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
    }),
  );

  test_parse(
    "!-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Not,
      val: Box::new(Node::UnExpr {
        op: lexer::Token::Sub,
        val: Box::new(Node::Int(5)),
      }),
    }),
  );
}

#[test]
fn test_bin_expr() {
  test_parse(
    "1 + 2",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    }),
  );

  test_parse(
    "(1 + 2)",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    }),
  );

  test_parse(
    "1 + 2 * 3",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::BinExpr {
        lhs: Box::new(Node::Int(2)),
        op: lexer::Token::Mul,
        rhs: Box::new(Node::Int(3)),
      }),
    }),
  );
}

#[test]
fn test_fn_expr() {
  test_parse(
    "|| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: Vec::new(),
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x,| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x,y| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x"), String::from("y")],
      expr: Box::new(Node::Int(5)),
    }),
  );
}

#[test]
fn test_decl() {
  test_parse("x", &parse_decl, Ok(Var::Single(String::from("x"))));

  test_parse(
    "[x]",
    &parse_decl,
    Ok(Var::Multi(vec![Var::Single(String::from("x"))])),
  );

  test_parse(
    "[x, y]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Single(String::from("y")),
    ])),
  );

  test_parse(
    "[[x, y], z]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Multi(vec![
        Var::Single(String::from("x")),
        Var::Single(String::from("y")),
      ]),
      Var::Single(String::from("z")),
    ])),
  );

  test_parse(
    "[x, [y, z]]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Multi(vec![
        Var::Single(String::from("y")),
        Var::Single(String::from("z")),
      ]),
    ])),
  );

  test_parse(
    "[[x], [y]]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Multi(vec![Var::Single(String::from("x"))]),
      Var::Multi(vec![Var::Single(String::from("y"))]),
    ])),
  );

  test_parse(
    "[x, [y, z], q]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Multi(vec![
        Var::Single(String::from("y")),
        Var::Single(String::from("z")),
      ]),
      Var::Single(String::from("q")),
    ])),
  );
}

#[test]
fn test_return_stmt() {
  test_parse("return", &parse_stmt, Ok(Node::Return(None)));

  test_parse(
    "return 5",
    &parse_stmt,
    Ok(Node::Return(Some(Box::new(Node::Int(5))))),
  );

  test_parse(
    "return fn()
       return 5",
    &parse_stmt,
    Ok(Node::Return(Some(Box::new(Node::Func {
      params: Vec::new(),
      body: vec![Node::Return(Some(Box::new(Node::Int(5))))],
    })))),
  );
}

#[test]
fn test_if_stmt() {
  test_parse(
    "if true
       pass",
    &parse_stmt,
    Ok(Node::If {
      cond: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );

  test_parse(
    "else if true
       pass",
    &parse_stmt,
    Ok(Node::ElseIf {
      cond: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );

  test_parse(
    "else
       pass",
    &parse_stmt,
    Ok(Node::Else {
      body: vec![Node::Pass],
    }),
  );
}
<commit_msg>tests.parser: Fix use of parse_un_expr<commit_after>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;
use std::fmt::Debug;
use std::cmp::PartialEq;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

fn test_parse<T: Debug + PartialEq>(
  source: &str,
  func: &Fn(&mut ParseIter) -> Result<T, ParseErrorKind>,
  expect: Result<T, ParseErrorKind>,
) {
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(func(&mut it), expect);

  assert_eq!(func(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();

  assert_eq!(func(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();

  assert_eq!(func(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_quark() {
  test_parse("null", &parse_quark, Ok(Node::Null));
  test_parse("true", &parse_quark, Ok(Node::Bool(true)));
  test_parse("false", &parse_quark, Ok(Node::Bool(false)));
  test_parse("1.3", &parse_quark, Ok(Node::Float(1.3)));
  test_parse("0.3", &parse_quark, Ok(Node::Float(0.3)));
  test_parse("2", &parse_quark, Ok(Node::Int(2)));
  test_parse("3", &parse_quark, Ok(Node::Int(3)));
  test_parse("name", &parse_quark, Ok(Node::Name(String::from("name"))));
  test_parse("table", &parse_quark, Ok(Node::Table));
}

#[test]
fn test_atom() {
  test_parse("null", &parse_atom, Ok(Node::Null));

  test_parse("(null)", &parse_atom, Ok(Node::Null));
}

#[test]
fn test_simple() {
  test_parse("foo", &parse_simple, Ok(Node::Name(String::from("foo"))));
  test_parse(
    "foo.bar",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    }),
  );
  test_parse(
    "foo[bar]",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Name(String::from("bar"))),
    }),
  );
  test_parse(
    "foo()",
    &parse_simple,
    Ok(Node::Call {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo:bar()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Name(String::from("foo"))),
      method: Box::new(Node::Str(String::from("bar"))),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo.bar()",
    &parse_simple,
    Ok(Node::Call {
      func: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo.bar[baz]:qux()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Index {
        lhs: Box::new(Node::Index {
          lhs: Box::new(Node::Name(String::from("foo"))),
          rhs: Box::new(Node::Str(String::from("bar"))),
        }),
        rhs: Box::new(Node::Name(String::from("baz"))),
      }),
      method: Box::new(Node::Str(String::from("qux"))),
      args: Vec::new(),
    }),
  );
}

#[test]
fn test_fn_args() {
  test_parse("()", &parse_fn_args, Ok(Vec::new()));
}

#[test]
fn test_un_expr() {
  test_parse("5", &parse_un_expr, Ok(Node::Int(5)));

  test_parse(
    "foo()",
    &parse_un_expr,
    Ok(Node::Call {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    }),
  );

  test_parse(
    "-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "-foo.bar",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
    }),
  );

  test_parse(
    "!-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Not,
      val: Box::new(Node::UnExpr {
        op: lexer::Token::Sub,
        val: Box::new(Node::Int(5)),
      }),
    }),
  );
}

#[test]
fn test_bin_expr() {
  test_parse(
    "1 + 2",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    }),
  );

  test_parse(
    "(1 + 2)",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    }),
  );

  test_parse(
    "1 + 2 * 3",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::BinExpr {
        lhs: Box::new(Node::Int(2)),
        op: lexer::Token::Mul,
        rhs: Box::new(Node::Int(3)),
      }),
    }),
  );
}

#[test]
fn test_fn_expr() {
  test_parse(
    "|| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: Vec::new(),
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x,| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x,y| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x"), String::from("y")],
      expr: Box::new(Node::Int(5)),
    }),
  );
}

#[test]
fn test_decl() {
  test_parse("x", &parse_decl, Ok(Var::Single(String::from("x"))));

  test_parse(
    "[x]",
    &parse_decl,
    Ok(Var::Multi(vec![Var::Single(String::from("x"))])),
  );

  test_parse(
    "[x, y]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Single(String::from("y")),
    ])),
  );

  test_parse(
    "[[x, y], z]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Multi(vec![
        Var::Single(String::from("x")),
        Var::Single(String::from("y")),
      ]),
      Var::Single(String::from("z")),
    ])),
  );

  test_parse(
    "[x, [y, z]]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Multi(vec![
        Var::Single(String::from("y")),
        Var::Single(String::from("z")),
      ]),
    ])),
  );

  test_parse(
    "[[x], [y]]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Multi(vec![Var::Single(String::from("x"))]),
      Var::Multi(vec![Var::Single(String::from("y"))]),
    ])),
  );

  test_parse(
    "[x, [y, z], q]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Multi(vec![
        Var::Single(String::from("y")),
        Var::Single(String::from("z")),
      ]),
      Var::Single(String::from("q")),
    ])),
  );
}

#[test]
fn test_return_stmt() {
  test_parse("return", &parse_stmt, Ok(Node::Return(None)));

  test_parse(
    "return 5",
    &parse_stmt,
    Ok(Node::Return(Some(Box::new(Node::Int(5))))),
  );

  test_parse(
    "return fn()
       return 5",
    &parse_stmt,
    Ok(Node::Return(Some(Box::new(Node::Func {
      params: Vec::new(),
      body: vec![Node::Return(Some(Box::new(Node::Int(5))))],
    })))),
  );
}

#[test]
fn test_if_stmt() {
  test_parse(
    "if true
       pass",
    &parse_stmt,
    Ok(Node::If {
      cond: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );

  test_parse(
    "else if true
       pass",
    &parse_stmt,
    Ok(Node::ElseIf {
      cond: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );

  test_parse(
    "else
       pass",
    &parse_stmt,
    Ok(Node::Else {
      body: vec![Node::Pass],
    }),
  );
}
<|endoftext|>