<commit_before>extern crate rand;
use super::prng::LTPrng;
use super::soliton::RobustSolitonCDF;

pub struct LTBlockSampler {
  k: u32,
  prng: LTPrng,
  cdf: RobustSolitonCDF
}

#[derive(Debug)]
pub struct LTBlockSpec {
  seed: u64,
  degree: u32,
  srcblock_ids: Vec<u32>
}

impl LTBlockSampler {
  pub fn new(params: LTBlockSamplerParams) -> Self {
    return LTBlockSampler {
      k: params.k,
      prng: LTPrng::new(params.seed),
      cdf: RobustSolitonCDF::new(params.k, params.c, params.delta)
    }
  }

  pub fn seed(&mut self, seed: u64) {
    self.prng.seed(seed);
  }

  pub fn next(&mut self) -> LTBlockSpec {
    let seed = self.prng.current();
    let degree = self.sample_degree();

    let mut n = 0;
    let mut srcblock_ids : Vec<u32> = vec!();
    while n < degree {
      let block_id = (self.prng.next() as u32 % self.k) as u32;
      if !srcblock_ids.contains(&block_id) {
        srcblock_ids.push(block_id);
        n += 1;
      }
    }
    LTBlockSpec {
      seed: seed,
      degree: degree,
      srcblock_ids: srcblock_ids
    }
  }

  fn sample_degree(&mut self) -> u32 {
    let sample = self.prng.next() as f64 / self.prng.upper_bound() as f64;

    // Add 1 to 0-indexed CDF
    self.cdf.get_index(sample) as u32 + 1
  }
}

impl Iterator for LTBlockSampler {
  type Item = LTBlockSpec;

  fn next(&mut self) -> Option<LTBlockSpec> {
    Some(self.next())
  }
}

pub struct LTBlockSamplerParams {
  k: u32,
  seed: u64,
  delta: f64,
  c: f64
}

impl LTBlockSamplerParams {
  pub fn new(num_blocks: u32) -> Self {
    return LTBlockSamplerParams {
      k: num_blocks,

      // Default parameters for Robust Soliton Distribution
      seed: rand::random::<u64>(),
      c: 0.1f64,
      delta: 0.5f64
    }
  }
  pub fn seed(&self, new_seed: u64) -> Self {
    return LTBlockSamplerParams {
      seed: new_seed,
      .. *self
    }
  }
  pub fn c(&self, new_c: f64) -> Self {
   return LTBlockSamplerParams {
    c: new_c,
    .. *self
   }
  }
  pub fn delta(&self, new_delta: f64) -> Self {
   return LTBlockSamplerParams {
    delta: new_delta,
    .. *self
   }
  }
}

#[test]
fn blocks_sequence() {
  let num_blocks = 571;
  let seed = 166362120;
  let expected : Vec<Vec<u32>> = vec!(vec!(98), vec!(400, 62));
  let params = LTBlockSamplerParams::new(num_blocks).seed(seed);
  let sampler = LTBlockSampler::new(params);
  for (block, exp_block) in sampler.zip(expected.iter()) {
    assert_eq!(block.srcblock_ids, *exp_block);
  }
}

<commit_msg>more test material for sampler<commit_after>extern crate rand;
use super::prng::LTPrng;
use super::soliton::RobustSolitonCDF;

pub struct LTBlockSampler {
  k: u32,
  prng: LTPrng,
  cdf: RobustSolitonCDF
}

#[derive(Debug)]
pub struct LTBlockSpec {
  seed: u64,
  degree: u32,
  srcblock_ids: Vec<u32>
}

impl LTBlockSampler {
  pub fn new(params: LTBlockSamplerParams) -> Self {
    return LTBlockSampler {
      k: params.k,
      prng: LTPrng::new(params.seed),
      cdf: RobustSolitonCDF::new(params.k, params.c, params.delta)
    }
  }

  pub fn seed(&mut self, seed: u64) {
    self.prng.seed(seed);
  }

  pub fn next(&mut self) -> LTBlockSpec {
    let seed = self.prng.current();
    let degree = self.sample_degree();

    let mut n = 0;
    let mut srcblock_ids : Vec<u32> = vec!();
    while n < degree {
      let block_id = (self.prng.next() as u32 % self.k) as u32;
      if !srcblock_ids.contains(&block_id) {
        srcblock_ids.push(block_id);
        n += 1;
      }
    }
    LTBlockSpec {
      seed: seed,
      degree: degree,
      srcblock_ids: srcblock_ids
    }
  }

  fn sample_degree(&mut self) -> u32 {
    let sample = self.prng.next() as f64 / self.prng.upper_bound() as f64;

    // Add 1 to 0-indexed CDF
    self.cdf.get_index(sample) as u32 + 1
  }
}

impl Iterator for LTBlockSampler {
  type Item = LTBlockSpec;

  fn next(&mut self) -> Option<LTBlockSpec> {
    Some(self.next())
  }
}

pub struct LTBlockSamplerParams {
  k: u32,
  seed: u64,
  delta: f64,
  c: f64
}

impl LTBlockSamplerParams {
  pub fn new(num_blocks: u32) -> Self {
    return LTBlockSamplerParams {
      k: num_blocks,

      // Default parameters for Robust Soliton Distribution
      seed: rand::random::<u64>(),
      c: 0.1f64,
      delta: 0.5f64
    }
  }
  pub fn seed(&self, new_seed: u64) -> Self {
    return LTBlockSamplerParams {
      seed: new_seed,
      .. *self
    }
  }
  pub fn c(&self, new_c: f64) -> Self {
   return LTBlockSamplerParams {
    c: new_c,
    .. *self
   }
  }
  pub fn delta(&self, new_delta: f64) -> Self {
   return LTBlockSamplerParams {
    delta: new_delta,
    .. *self
   }
  }
}

#[test]
fn blocks_sequence() {
  let num_blocks = 571;
  let seed = 166362120;
  let expected : Vec<Vec<u32>> = vec!(vec!(98),
                                      vec!(400, 62),
                                      vec!(49, 385),
                                      vec!(421, 541),
                                      vec!(336, 109, 412, 410, 463, 231, 319, 564, 417, 305, 313, 461));
  let params = LTBlockSamplerParams::new(num_blocks).seed(seed);
  let sampler = LTBlockSampler::new(params);
  for (block, exp_block) in sampler.zip(expected.iter()) {
    assert_eq!(block.srcblock_ids, *exp_block);
  }
}

<|endoftext|>


<commit_before>#[derive(Clone, Copy)]
pub struct True;
#[derive(Clone, Copy)]
pub struct False;

impl True {
    pub const fn not<'a>(&'a self) -> &'a False {
        &False
    }
    pub const fn and<'a, T>(&'a self, other: &'a T) -> &'a T {
        other
    }
    pub const fn or<'a, T>(&'a self, _: &'a T) -> &'a True {
        &True
    }
}

impl False {
    pub const fn not<'a>(&'a self) -> &'a True {
        &True
    }
    pub const fn and<'a, T>(&'a self, _: &'a T) -> &'a False {
        &False
    }
    pub const fn or<'a, T>(&'a self, other: &'a T) -> &'a T {
        other
    }
}

pub trait ToBool: Sized {
    type Bool: Sized;
    const TO_BOOL: Self::Bool;
}

impl ToBool for [(); 0] {
    type Bool = False;
    const TO_BOOL: Self::Bool = False;
}

impl ToBool for [(); 1] {
    type Bool = True;
    const TO_BOOL: Self::Bool = True;
}

/// Converts a `const bool` to a type-level boolean.
#[doc(hidden)]
#[macro_export]
macro_rules! _to_bool {
    ($x:expr) => {{
        const X: bool = $x;
        <[(); X as usize] as $crate::_bool::ToBool>::TO_BOOL
    }};
}
<commit_msg>Expose exact lifetimes on `True`/`False` methods<commit_after>#[derive(Clone, Copy)]
pub struct True;
#[derive(Clone, Copy)]
pub struct False;

impl True {
    pub const fn not(&self) -> &'static False {
        &False
    }
    pub const fn and<'a, T>(&self, other: &'a T) -> &'a T {
        other
    }
    pub const fn or<T>(&self, _: &T) -> &'static True {
        &True
    }
}

impl False {
    pub const fn not(&self) -> &'static True {
        &True
    }
    pub const fn and<T>(&self, _: &T) -> &'static False {
        &False
    }
    pub const fn or<'a, T>(&self, other: &'a T) -> &'a T {
        other
    }
}

pub trait ToBool: Sized {
    type Bool: Sized;
    const TO_BOOL: Self::Bool;
}

impl ToBool for [(); 0] {
    type Bool = False;
    const TO_BOOL: Self::Bool = False;
}

impl ToBool for [(); 1] {
    type Bool = True;
    const TO_BOOL: Self::Bool = True;
}

/// Converts a `const bool` to a type-level boolean.
#[doc(hidden)]
#[macro_export]
macro_rules! _to_bool {
    ($x:expr) => {{
        const X: bool = $x;
        <[(); X as usize] as $crate::_bool::ToBool>::TO_BOOL
    }};
}
<|endoftext|>


<commit_before>//! C API for mp4parse module.
//!
//! Parses ISO Base Media Format aka video/mp4 streams.
//!
//! # Examples
//!
//! ```rust
//! extern crate mp4parse;
//!
//! // Minimal valid mp4 containing no tracks.
//! let data = b"\0\0\0\x10ftypmp42\0\0\0\0";
//!
//! let context = mp4parse::mp4parse_new();
//! unsafe {
//!     let rv = mp4parse::mp4parse_read(context, data.as_ptr(), data.len());
//!     assert_eq!(rv, mp4parse::mp4parse_error::MP4PARSE_OK);
//!     mp4parse::mp4parse_free(context);
//! }
//! ```

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std;
use std::io::Cursor;

// Symbols we need from our rust api.
use MediaContext;
use TrackType;
use read_mp4;
use Error;
use media_time_to_ms;
use track_time_to_ms;
use SampleEntry;

#[repr(C)]
#[derive(PartialEq,Debug)]
pub enum mp4parse_error {
    MP4PARSE_OK = 0,
    MP4PARSE_ERROR_BADARG = 1,
    MP4PARSE_ERROR_INVALID = 2,
    MP4PARSE_ERROR_UNSUPPORTED = 3,
    MP4PARSE_ERROR_EOF = 4,
    MP4PARSE_ERROR_ASSERT = 5,
    MP4PARSE_ERROR_IO = 6,
}

#[repr(C)]
pub enum mp4parse_track_type {
    MP4PARSE_TRACK_TYPE_VIDEO = 0,
    MP4PARSE_TRACK_TYPE_AUDIO = 1,
}

#[repr(C)]
pub struct mp4parse_track_info {
    pub track_type: mp4parse_track_type,
    pub track_id: u32,
    pub duration: u64,
    pub media_time: i64, // wants to be u64? understand how elst adjustment works
    // TODO(kinetik): include crypto guff
}

#[repr(C)]
pub struct mp4parse_track_audio_info {
    pub channels: u16,
    pub bit_depth: u16,
    pub sample_rate: u32,
    // TODO(kinetik):
    // int32_t profile;
    // int32_t extended_profile; // check types
    // extra_data
    // codec_specific_config
}

#[repr(C)]
pub struct mp4parse_track_video_info {
    pub display_width: u32,
    pub display_height: u32,
    pub image_width: u16,
    pub image_height: u16,
    // TODO(kinetik):
    // extra_data
    // codec_specific_config
}

#[repr(C)]
#[allow(non_camel_case_types)]
pub struct mp4parse_state(MediaContext);

// C API wrapper functions.

/// Allocate an opaque rust-side parser context.
#[no_mangle]
pub extern "C" fn mp4parse_new() -> *mut mp4parse_state {
    let context = Box::new(mp4parse_state(MediaContext::new()));
    Box::into_raw(context)
}

/// Free a rust-side parser context.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_free(context: *mut mp4parse_state) {
    assert!(!context.is_null());
    let _ = Box::from_raw(context);
}

/// Feed a buffer through `read_mp4()` with the given rust-side
/// parser context, returning success or an error code.
///
/// This is safe to call with NULL arguments but will crash
/// if given invalid pointers, as is usual for C.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_read(context: *mut mp4parse_state, buffer: *const u8, size: usize) -> mp4parse_error {
    // Validate arguments from C.
    if context.is_null() || buffer.is_null() || size < 8 {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let mut context: &mut MediaContext = &mut (*context).0;

    // Wrap the buffer we've been give in a slice.
    let b = std::slice::from_raw_parts(buffer, size);
    let mut c = Cursor::new(b);

    // Parse in a subthread to catch any panics.
    let task = std::thread::spawn(move || read_mp4(&mut c, &mut context));
    // The task's JoinHandle will return an error result if the
    // thread panicked, and will wrap the closure's return'd
    // result in an Ok(..) otherwise, meaning we could see
    // Ok(Err(Error::..)) here. So map thread failures back
    // to an mp4parse::Error before converting to a C return value.
    match task.join().unwrap_or(Err(Error::AssertCaught)) {
        Ok(_) => mp4parse_error::MP4PARSE_OK,
        Err(Error::InvalidData) => mp4parse_error::MP4PARSE_ERROR_INVALID,
        Err(Error::Unsupported) => mp4parse_error::MP4PARSE_ERROR_UNSUPPORTED,
        Err(Error::UnexpectedEOF) => mp4parse_error::MP4PARSE_ERROR_EOF,
        Err(Error::AssertCaught) => mp4parse_error::MP4PARSE_ERROR_ASSERT,
        Err(Error::Io(_)) => mp4parse_error::MP4PARSE_ERROR_IO,
    }
}

/// Return the number of tracks parsed by previous `read_mp4()` calls.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_count(context: *const mp4parse_state) -> u32 {
    // Validate argument from C.
    assert!(!context.is_null());
    let context: &MediaContext = &(*context).0;

    // Make sure the track count fits in a u32.
    assert!(context.tracks.len() < u32::max_value() as usize);
    context.tracks.len() as u32
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;
    let track_index: usize = track as usize;
    let info: &mut mp4parse_track_info = &mut *info;

    if track_index >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    info.track_type = match context.tracks[track_index].track_type {
        TrackType::Video => mp4parse_track_type::MP4PARSE_TRACK_TYPE_VIDEO,
        TrackType::Audio => mp4parse_track_type::MP4PARSE_TRACK_TYPE_AUDIO,
        TrackType::Unknown => return mp4parse_error::MP4PARSE_ERROR_UNSUPPORTED,
    };

    // Maybe context & track should just have a single simple is_valid() instead?
    if context.timescale.is_none() ||
       context.tracks[track_index].timescale.is_none() ||
       context.tracks[track_index].duration.is_none() ||
       context.tracks[track_index].track_id.is_none() {
        return mp4parse_error::MP4PARSE_ERROR_INVALID;
    }

    std::thread::spawn(move || {
        let track = &context.tracks[track_index];
        let empty_duration = if track.empty_duration.is_some() {
            media_time_to_ms(track.empty_duration.unwrap(), context.timescale.unwrap())
        } else {
            0
        };
        info.media_time = if track.media_time.is_some() {
            track_time_to_ms(track.media_time.unwrap(), track.timescale.unwrap()) as i64 - empty_duration as i64
        } else {
            0
        };
        info.duration = track_time_to_ms(track.duration.unwrap(), track.timescale.unwrap());
        info.track_id = track.track_id.unwrap();
        mp4parse_error::MP4PARSE_OK
    }).join().unwrap_or(mp4parse_error::MP4PARSE_ERROR_INVALID)
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_audio_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_audio_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;

    if track as usize >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let track = &context.tracks[track as usize];

    match track.track_type {
        TrackType::Audio => {}
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let audio = match track.data {
        Some(ref data) => data,
        None => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let audio = match *audio {
        SampleEntry::Audio(ref x) => x,
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    (*info).channels = audio.channelcount;
    (*info).bit_depth = audio.samplesize;
    (*info).sample_rate = audio.samplerate >> 16; // 16.16 fixed point

    mp4parse_error::MP4PARSE_OK
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_video_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_video_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;

    if track as usize >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let track = &context.tracks[track as usize];

    match track.track_type {
        TrackType::Video => {}
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let video = match track.data {
        Some(ref data) => data,
        None => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let video = match *video {
        SampleEntry::Video(ref x) => x,
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    if let Some(ref tkhd) = track.tkhd {
        (*info).display_width = tkhd.width >> 16; // 16.16 fixed point
        (*info).display_height = tkhd.height >> 16; // 16.16 fixed point
    } else {
        return mp4parse_error::MP4PARSE_ERROR_INVALID;
    }
    (*info).image_width = video.width;
    (*info).image_height = video.height;

    mp4parse_error::MP4PARSE_OK
}

#[test]
fn new_context() {
    let context = mp4parse_new();
    assert!(!context.is_null());
    unsafe {
        mp4parse_free(context);
    }
}

#[test]
#[should_panic(expected = "assertion failed")]
fn free_null_context() {
    unsafe {
        mp4parse_free(std::ptr::null_mut());
    }
}

#[test]
fn arg_validation() {
    let null_buffer = std::ptr::null();
    let null_context = std::ptr::null_mut();

    let context = mp4parse_new();
    assert!(!context.is_null());

    let buffer = vec![0u8; 8];

    unsafe {
        assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                   mp4parse_read(null_context, null_buffer, 0));
        assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                   mp4parse_read(context, null_buffer, 0));
    }

    for size in 0..buffer.len() {
        println!("testing buffer length {}", size);
        unsafe {
            assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                       mp4parse_read(context, buffer.as_ptr(), size));
        }
    }

    unsafe {
        mp4parse_free(context);
    }
}
<commit_msg>Drop thread wrapper from inside mp4parse_get_track_info.<commit_after>//! C API for mp4parse module.
//!
//! Parses ISO Base Media Format aka video/mp4 streams.
//!
//! # Examples
//!
//! ```rust
//! extern crate mp4parse;
//!
//! // Minimal valid mp4 containing no tracks.
//! let data = b"\0\0\0\x10ftypmp42\0\0\0\0";
//!
//! let context = mp4parse::mp4parse_new();
//! unsafe {
//!     let rv = mp4parse::mp4parse_read(context, data.as_ptr(), data.len());
//!     assert_eq!(rv, mp4parse::mp4parse_error::MP4PARSE_OK);
//!     mp4parse::mp4parse_free(context);
//! }
//! ```

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std;
use std::io::Cursor;

// Symbols we need from our rust api.
use MediaContext;
use TrackType;
use read_mp4;
use Error;
use media_time_to_ms;
use track_time_to_ms;
use SampleEntry;

#[repr(C)]
#[derive(PartialEq,Debug)]
pub enum mp4parse_error {
    MP4PARSE_OK = 0,
    MP4PARSE_ERROR_BADARG = 1,
    MP4PARSE_ERROR_INVALID = 2,
    MP4PARSE_ERROR_UNSUPPORTED = 3,
    MP4PARSE_ERROR_EOF = 4,
    MP4PARSE_ERROR_ASSERT = 5,
    MP4PARSE_ERROR_IO = 6,
}

#[repr(C)]
pub enum mp4parse_track_type {
    MP4PARSE_TRACK_TYPE_VIDEO = 0,
    MP4PARSE_TRACK_TYPE_AUDIO = 1,
}

#[repr(C)]
pub struct mp4parse_track_info {
    pub track_type: mp4parse_track_type,
    pub track_id: u32,
    pub duration: u64,
    pub media_time: i64, // wants to be u64? understand how elst adjustment works
    // TODO(kinetik): include crypto guff
}

#[repr(C)]
pub struct mp4parse_track_audio_info {
    pub channels: u16,
    pub bit_depth: u16,
    pub sample_rate: u32,
    // TODO(kinetik):
    // int32_t profile;
    // int32_t extended_profile; // check types
    // extra_data
    // codec_specific_config
}

#[repr(C)]
pub struct mp4parse_track_video_info {
    pub display_width: u32,
    pub display_height: u32,
    pub image_width: u16,
    pub image_height: u16,
    // TODO(kinetik):
    // extra_data
    // codec_specific_config
}

#[repr(C)]
#[allow(non_camel_case_types)]
pub struct mp4parse_state(MediaContext);

// C API wrapper functions.

/// Allocate an opaque rust-side parser context.
#[no_mangle]
pub extern "C" fn mp4parse_new() -> *mut mp4parse_state {
    let context = Box::new(mp4parse_state(MediaContext::new()));
    Box::into_raw(context)
}

/// Free a rust-side parser context.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_free(context: *mut mp4parse_state) {
    assert!(!context.is_null());
    let _ = Box::from_raw(context);
}

/// Feed a buffer through `read_mp4()` with the given rust-side
/// parser context, returning success or an error code.
///
/// This is safe to call with NULL arguments but will crash
/// if given invalid pointers, as is usual for C.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_read(context: *mut mp4parse_state, buffer: *const u8, size: usize) -> mp4parse_error {
    // Validate arguments from C.
    if context.is_null() || buffer.is_null() || size < 8 {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let mut context: &mut MediaContext = &mut (*context).0;

    // Wrap the buffer we've been give in a slice.
    let b = std::slice::from_raw_parts(buffer, size);
    let mut c = Cursor::new(b);

    // Parse in a subthread to catch any panics.
    let task = std::thread::spawn(move || read_mp4(&mut c, &mut context));
    // The task's JoinHandle will return an error result if the
    // thread panicked, and will wrap the closure's return'd
    // result in an Ok(..) otherwise, meaning we could see
    // Ok(Err(Error::..)) here. So map thread failures back
    // to an mp4parse::Error before converting to a C return value.
    match task.join().unwrap_or(Err(Error::AssertCaught)) {
        Ok(_) => mp4parse_error::MP4PARSE_OK,
        Err(Error::InvalidData) => mp4parse_error::MP4PARSE_ERROR_INVALID,
        Err(Error::Unsupported) => mp4parse_error::MP4PARSE_ERROR_UNSUPPORTED,
        Err(Error::UnexpectedEOF) => mp4parse_error::MP4PARSE_ERROR_EOF,
        Err(Error::AssertCaught) => mp4parse_error::MP4PARSE_ERROR_ASSERT,
        Err(Error::Io(_)) => mp4parse_error::MP4PARSE_ERROR_IO,
    }
}

/// Return the number of tracks parsed by previous `read_mp4()` calls.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_count(context: *const mp4parse_state) -> u32 {
    // Validate argument from C.
    assert!(!context.is_null());
    let context: &MediaContext = &(*context).0;

    // Make sure the track count fits in a u32.
    assert!(context.tracks.len() < u32::max_value() as usize);
    context.tracks.len() as u32
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;
    let track_index: usize = track as usize;
    let info: &mut mp4parse_track_info = &mut *info;

    if track_index >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    info.track_type = match context.tracks[track_index].track_type {
        TrackType::Video => mp4parse_track_type::MP4PARSE_TRACK_TYPE_VIDEO,
        TrackType::Audio => mp4parse_track_type::MP4PARSE_TRACK_TYPE_AUDIO,
        TrackType::Unknown => return mp4parse_error::MP4PARSE_ERROR_UNSUPPORTED,
    };

    // Maybe context & track should just have a single simple is_valid() instead?
    if context.timescale.is_none() ||
       context.tracks[track_index].timescale.is_none() ||
       context.tracks[track_index].duration.is_none() ||
       context.tracks[track_index].track_id.is_none() {
        return mp4parse_error::MP4PARSE_ERROR_INVALID;
    }

    let track = &context.tracks[track_index];
    let empty_duration = if track.empty_duration.is_some() {
        media_time_to_ms(track.empty_duration.unwrap(), context.timescale.unwrap())
    } else {
        0
    };
    info.media_time = if track.media_time.is_some() {
        track_time_to_ms(track.media_time.unwrap(), track.timescale.unwrap()) as i64 - empty_duration as i64
    } else {
        0
    };
    info.duration = track_time_to_ms(track.duration.unwrap(), track.timescale.unwrap());
    info.track_id = track.track_id.unwrap();

    mp4parse_error::MP4PARSE_OK
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_audio_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_audio_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;

    if track as usize >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let track = &context.tracks[track as usize];

    match track.track_type {
        TrackType::Audio => {}
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let audio = match track.data {
        Some(ref data) => data,
        None => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let audio = match *audio {
        SampleEntry::Audio(ref x) => x,
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    (*info).channels = audio.channelcount;
    (*info).bit_depth = audio.samplesize;
    (*info).sample_rate = audio.samplerate >> 16; // 16.16 fixed point

    mp4parse_error::MP4PARSE_OK
}

#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_video_info(context: *mut mp4parse_state, track: u32, info: *mut mp4parse_track_video_info) -> mp4parse_error {
    if context.is_null() || info.is_null() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let context: &mut MediaContext = &mut (*context).0;

    if track as usize >= context.tracks.len() {
        return mp4parse_error::MP4PARSE_ERROR_BADARG;
    }

    let track = &context.tracks[track as usize];

    match track.track_type {
        TrackType::Video => {}
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let video = match track.data {
        Some(ref data) => data,
        None => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    let video = match *video {
        SampleEntry::Video(ref x) => x,
        _ => return mp4parse_error::MP4PARSE_ERROR_INVALID,
    };

    if let Some(ref tkhd) = track.tkhd {
        (*info).display_width = tkhd.width >> 16; // 16.16 fixed point
        (*info).display_height = tkhd.height >> 16; // 16.16 fixed point
    } else {
        return mp4parse_error::MP4PARSE_ERROR_INVALID;
    }
    (*info).image_width = video.width;
    (*info).image_height = video.height;

    mp4parse_error::MP4PARSE_OK
}

#[test]
fn new_context() {
    let context = mp4parse_new();
    assert!(!context.is_null());
    unsafe {
        mp4parse_free(context);
    }
}

#[test]
#[should_panic(expected = "assertion failed")]
fn free_null_context() {
    unsafe {
        mp4parse_free(std::ptr::null_mut());
    }
}

#[test]
fn arg_validation() {
    let null_buffer = std::ptr::null();
    let null_context = std::ptr::null_mut();

    let context = mp4parse_new();
    assert!(!context.is_null());

    let buffer = vec![0u8; 8];

    unsafe {
        assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                   mp4parse_read(null_context, null_buffer, 0));
        assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                   mp4parse_read(context, null_buffer, 0));
    }

    for size in 0..buffer.len() {
        println!("testing buffer length {}", size);
        unsafe {
            assert_eq!(mp4parse_error::MP4PARSE_ERROR_BADARG,
                       mp4parse_read(context, buffer.as_ptr(), size));
        }
    }

    unsafe {
        mp4parse_free(context);
    }
}
<|endoftext|>


<commit_before>//! Contains arm-specific types

pub use arch::arch_builder::arm::*;
use arch::DetailsArchInsn;
use capstone_sys::{arm_op_mem, arm_op_type, cs_arm, cs_arm_op};
use instruction::{RegId, RegIdInt};
use std::convert::From;
use std::os::raw::c_uint;
use std::{cmp, fmt, slice};

pub use capstone_sys::arm_insn_group as ArmInsnGroup;
pub use capstone_sys::arm_insn as ArmInsn;
pub use capstone_sys::arm_reg as ArmReg;

pub use capstone_sys::arm_vectordata_type as ArmVectorData;
pub use capstone_sys::arm_cpsmode_type as ArmCPSMode;
pub use capstone_sys::arm_cpsflag_type as ArmCPSFlag;
pub use capstone_sys::arm_cc as ArmCC;
pub use capstone_sys::arm_mem_barrier as ArmMemBarrier;
pub use capstone_sys::arm_setend_type as ArmSetendType;
use capstone_sys::{arm_shifter, cs_arm_op__bindgen_ty_2};

/// Contains ARM-specific details for an instruction
pub struct ArmInsnDetail<'a>(pub(crate) &'a cs_arm);

/// ARM shift amount
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum ArmShift {
    Invalid,

    /// Arithmetic shift right (immediate)
    Asr(u32),

    /// Logical shift lift (immediate)
    Lsl(u32),

    /// Logical shift right (immediate)
    Lsr(u32),

    /// Rotate right (immediate)
    Ror(u32),

    /// Rotate right with extend (immediate)
    Rrx(u32),

    /// Arithmetic shift right (register)
    AsrReg(RegId),

    /// Logical shift lift (register)
    LslReg(RegId),

    /// Logical shift right (register)
    LsrReg(RegId),

    /// Rotate right (register)
    RorReg(RegId),

    /// Rotate right with extend (register)
    RrxReg(RegId),
}

impl ArmShift {
    fn new(type_: arm_shifter, value: c_uint) -> ArmShift {
        use self::arm_shifter::*;
        use self::ArmShift::*;

        macro_rules! arm_shift_match {
            (
                imm = [ $( $imm_r_enum:ident = $imm_c_enum:ident, )* ]
                reg = [ $( $reg_r_enum:ident = $reg_c_enum:ident, )* ]
            ) => {
                match type_ {
                    ARM_SFT_INVALID => Invalid,

                    $(
                        $imm_c_enum => $imm_r_enum(value as u32) ,
                    )*
                    $(
                        $reg_c_enum => $reg_r_enum(RegId(value as RegIdInt)) ,
                    )*
                }
            }
        };

        arm_shift_match!(
            imm = [
                Asr = ARM_SFT_ASR, Lsl = ARM_SFT_LSL, Lsr = ARM_SFT_LSR,
                Ror = ARM_SFT_ROR, Rrx = ARM_SFT_RRX,
            ]
            reg = [
                AsrReg = ARM_SFT_ASR_REG, LslReg = ARM_SFT_LSL_REG, LsrReg = ARM_SFT_LSR_REG,
                RorReg = ARM_SFT_ROR_REG, RrxReg = ARM_SFT_RRX_REG,
            ]
        )
    }
}

impl ArmOperandType {
    fn new(op_type: arm_op_type, value: cs_arm_op__bindgen_ty_2) -> ArmOperandType {
        use self::arm_op_type::*;
        use self::ArmOperandType::*;

        match op_type {
            ARM_OP_INVALID => Invalid,
            ARM_OP_REG => Reg(RegId(unsafe { value.reg } as RegIdInt)),
            ARM_OP_IMM => Imm(unsafe { value.imm }),
            ARM_OP_MEM => Mem(ArmOpMem(unsafe { value.mem })),
            ARM_OP_FP => Fp(unsafe { value.fp }),
            ARM_OP_CIMM => Cimm(unsafe { value.imm }),
            ARM_OP_PIMM => Pimm(unsafe { value.imm }),
            ARM_OP_SETEND => Setend(unsafe { value.setend }),
            ARM_OP_SYSREG => SysReg(RegId(unsafe { value.reg } as RegIdInt)),
        }
    }
}

/// ARM operand
#[derive(Clone, Debug, PartialEq)]
pub struct ArmOperand {
    /// Vector Index for some vector operands
    pub vector_index: Option<u32>,

    /// Whether operand is subtracted
    pub subtracted: bool,

    pub shift: ArmShift,

    /// Operand type
    pub op_type: ArmOperandType,
}

/// ARM operand
#[derive(Clone, Debug, PartialEq)]
pub enum ArmOperandType {
    /// Register
    Reg(RegId),

    /// Immediate
    Imm(i32),

    /// Memory
    Mem(ArmOpMem),

    /// Floating point
    Fp(f64),

    /// C-IMM
    Cimm(i32),

    /// P-IMM
    Pimm(i32),

    /// SETEND instruction endianness
    Setend(ArmSetendType),

    /// Sysreg
    SysReg(RegId),

    /// Invalid
    Invalid,
}

/// ARM memory operand
#[derive(Debug, Copy, Clone)]
pub struct ArmOpMem(pub(crate) arm_op_mem);

impl<'a> ArmInsnDetail<'a> {
    /// Whether the instruction is a user mode
    pub fn usermode(&self) -> bool {
        self.0.usermode
    }

    /// Vector size
    pub fn vector_size(&self) -> i32 {
        self.0.vector_size as i32
    }

    /// Type of vector data
    pub fn vector_data(&self) -> ArmVectorData {
        self.0.vector_data
    }

    /// CPS mode for CPS instruction
    pub fn cps_mode(&self) -> ArmCPSMode {
        self.0.cps_mode
    }

    /// CPS flag for CPS instruction
    pub fn cps_flag(&self) -> ArmCPSFlag {
        self.0.cps_flag
    }

    /// Condition codes
    pub fn cc(&self) -> ArmCC {
        self.0.cc
    }

    /// Whether this insn updates flags
    pub fn update_flags(&self) -> bool {
        self.0.update_flags
    }

    /// Whether writeback is required
    pub fn writeback(&self) -> bool {
        self.0.writeback
    }

    /// Memory barrier
    pub fn mem_barrier(&self) -> ArmMemBarrier {
        self.0.mem_barrier
    }
}

impl_PartialEq_repr_fields!(ArmInsnDetail<'a> [ 'a ];
    usermode, vector_size, vector_data, cps_mode, cps_flag, cc, update_flags, writeback,
    mem_barrier, operands
);

impl ArmOpMem {
    /// Base register
    pub fn base(&self) -> RegId {
        RegId(self.0.base as RegIdInt)
    }

    /// Index value
    pub fn index(&self) -> u32 {
        self.0.index as u32
    }

    /// Scale for index register (can be 1, or -1)
    pub fn scale(&self) -> i32 {
        self.0.scale as i32
    }

    /// Disp value
    pub fn disp(&self) -> i32 {
        self.0.disp as i32
    }
}

impl_PartialEq_repr_fields!(ArmOpMem;
    base, index, scale, disp
);

impl cmp::Eq for ArmOpMem {}

impl Default for ArmOperand {
    fn default() -> Self {
        ArmOperand {
            vector_index: None,
            subtracted: false,
            shift: ArmShift::Invalid,
            op_type: ArmOperandType::Invalid
        }
    }
}

impl<'a> From<&'a cs_arm_op> for ArmOperand {
    fn from(op: &cs_arm_op) -> ArmOperand {
        let shift = ArmShift::new(op.shift.type_, op.shift.value);
        let op_type = ArmOperandType::new(op.type_, op.__bindgen_anon_1);
        let vector_index = if op.vector_index >= 0 {
            Some(op.vector_index as u32)
        } else {
            None
        };
        ArmOperand {
            vector_index,
            shift,
            op_type,
            subtracted: op.subtracted,
        }
    }
}

def_arch_details_struct!(
    InsnDetail = ArmInsnDetail;
    Operand = ArmOperand;
    OperandIterator = ArmOperandIterator;
    OperandIteratorLife = ArmOperandIterator<'a>;
    [ pub struct ArmOperandIterator<'a>(slice::Iter<'a, cs_arm_op>); ]
    cs_arch_op = cs_arm_op;
    cs_arch = cs_arm;
);

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

    #[test]
    fn test_armshift() {
        use super::arm_shifter::*;
        use super::ArmShift::*;
        use std::os::raw::c_uint;

        fn t(shift_type_value: (arm_shifter, c_uint), arm_shift: ArmShift) {
            let (shift_type, value) = shift_type_value;
            assert_eq!(arm_shift, ArmShift::new(shift_type, value));
        }

        t((ARM_SFT_INVALID, 0), Invalid);
        t((ARM_SFT_ASR, 0), Asr(0));
        t((ARM_SFT_ASR_REG, 42), AsrReg(RegId(42)));
        t((ARM_SFT_RRX_REG, 42), RrxReg(RegId(42)));
    }

    #[test]
    fn test_arm_op_type() {
        use super::arm_op_type::*;
        use super::ArmOperandType::*;

        fn t(
            op_type_value: (arm_op_type, cs_arm_op__bindgen_ty_2),
            expected_op_type: ArmOperandType,
        ) {
            let (op_type, op_value) = op_type_value;
            let op_type = ArmOperandType::new(op_type, op_value);
            assert_eq!(expected_op_type, op_type);
        }

        t(
            (ARM_OP_INVALID, cs_arm_op__bindgen_ty_2 { reg: 0 }),
            Invalid,
        );
        t(
            (ARM_OP_REG, cs_arm_op__bindgen_ty_2 { reg: 0 }),
            Reg(RegId(0)),
        );
    }

    #[test]
    fn test_arm_insn_detail_eq() {
        let a1 = cs_arm {
            usermode: false,
            vector_size: 0,
            vector_data: arm_vectordata_type::ARM_VECTORDATA_INVALID,
            cps_mode: arm_cpsmode_type::ARM_CPSMODE_INVALID,
            cps_flag: arm_cpsflag_type::ARM_CPSFLAG_INVALID,
            cc: arm_cc::ARM_CC_INVALID,
            update_flags: false,
            writeback: false,
            mem_barrier: arm_mem_barrier::ARM_MB_INVALID,
            op_count: 0,
            operands: [
                cs_arm_op {
                    vector_index: 0,
                    shift: cs_arm_op__bindgen_ty_1 {
                        type_: arm_shifter::ARM_SFT_INVALID,
                        value: 0
                    },
                    type_: arm_op_type::ARM_OP_INVALID,
                    __bindgen_anon_1: cs_arm_op__bindgen_ty_2 { imm: 0 },
                    subtracted: false,
                }
            ; 36]
        };
        let a2 = cs_arm {
            usermode: true,
            ..a1
        };
        let a3 = cs_arm {
            op_count: 20,
            ..a1
        };
        let a4 = cs_arm {
            op_count: 19,
            ..a1
        };
        let a4_clone = a4.clone();
        assert_eq!(ArmInsnDetail(&a1), ArmInsnDetail(&a1));
        assert_ne!(ArmInsnDetail(&a1), ArmInsnDetail(&a2));
        assert_ne!(ArmInsnDetail(&a1), ArmInsnDetail(&a3));
        assert_ne!(ArmInsnDetail(&a3), ArmInsnDetail(&a4));
        assert_eq!(ArmInsnDetail(&a4), ArmInsnDetail(&a4_clone));
    }
}
<commit_msg>Treat ArmOpMem.index() as register<commit_after>//! Contains arm-specific types

pub use arch::arch_builder::arm::*;
use arch::DetailsArchInsn;
use capstone_sys::{arm_op_mem, arm_op_type, cs_arm, cs_arm_op};
use instruction::{RegId, RegIdInt};
use std::convert::From;
use std::os::raw::c_uint;
use std::{cmp, fmt, slice};

pub use capstone_sys::arm_insn_group as ArmInsnGroup;
pub use capstone_sys::arm_insn as ArmInsn;
pub use capstone_sys::arm_reg as ArmReg;

pub use capstone_sys::arm_vectordata_type as ArmVectorData;
pub use capstone_sys::arm_cpsmode_type as ArmCPSMode;
pub use capstone_sys::arm_cpsflag_type as ArmCPSFlag;
pub use capstone_sys::arm_cc as ArmCC;
pub use capstone_sys::arm_mem_barrier as ArmMemBarrier;
pub use capstone_sys::arm_setend_type as ArmSetendType;
use capstone_sys::{arm_shifter, cs_arm_op__bindgen_ty_2};

/// Contains ARM-specific details for an instruction
pub struct ArmInsnDetail<'a>(pub(crate) &'a cs_arm);

/// ARM shift amount
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum ArmShift {
    Invalid,

    /// Arithmetic shift right (immediate)
    Asr(u32),

    /// Logical shift lift (immediate)
    Lsl(u32),

    /// Logical shift right (immediate)
    Lsr(u32),

    /// Rotate right (immediate)
    Ror(u32),

    /// Rotate right with extend (immediate)
    Rrx(u32),

    /// Arithmetic shift right (register)
    AsrReg(RegId),

    /// Logical shift lift (register)
    LslReg(RegId),

    /// Logical shift right (register)
    LsrReg(RegId),

    /// Rotate right (register)
    RorReg(RegId),

    /// Rotate right with extend (register)
    RrxReg(RegId),
}

impl ArmShift {
    fn new(type_: arm_shifter, value: c_uint) -> ArmShift {
        use self::arm_shifter::*;
        use self::ArmShift::*;

        macro_rules! arm_shift_match {
            (
                imm = [ $( $imm_r_enum:ident = $imm_c_enum:ident, )* ]
                reg = [ $( $reg_r_enum:ident = $reg_c_enum:ident, )* ]
            ) => {
                match type_ {
                    ARM_SFT_INVALID => Invalid,

                    $(
                        $imm_c_enum => $imm_r_enum(value as u32) ,
                    )*
                    $(
                        $reg_c_enum => $reg_r_enum(RegId(value as RegIdInt)) ,
                    )*
                }
            }
        };

        arm_shift_match!(
            imm = [
                Asr = ARM_SFT_ASR, Lsl = ARM_SFT_LSL, Lsr = ARM_SFT_LSR,
                Ror = ARM_SFT_ROR, Rrx = ARM_SFT_RRX,
            ]
            reg = [
                AsrReg = ARM_SFT_ASR_REG, LslReg = ARM_SFT_LSL_REG, LsrReg = ARM_SFT_LSR_REG,
                RorReg = ARM_SFT_ROR_REG, RrxReg = ARM_SFT_RRX_REG,
            ]
        )
    }
}

impl ArmOperandType {
    fn new(op_type: arm_op_type, value: cs_arm_op__bindgen_ty_2) -> ArmOperandType {
        use self::arm_op_type::*;
        use self::ArmOperandType::*;

        match op_type {
            ARM_OP_INVALID => Invalid,
            ARM_OP_REG => Reg(RegId(unsafe { value.reg } as RegIdInt)),
            ARM_OP_IMM => Imm(unsafe { value.imm }),
            ARM_OP_MEM => Mem(ArmOpMem(unsafe { value.mem })),
            ARM_OP_FP => Fp(unsafe { value.fp }),
            ARM_OP_CIMM => Cimm(unsafe { value.imm }),
            ARM_OP_PIMM => Pimm(unsafe { value.imm }),
            ARM_OP_SETEND => Setend(unsafe { value.setend }),
            ARM_OP_SYSREG => SysReg(RegId(unsafe { value.reg } as RegIdInt)),
        }
    }
}

/// ARM operand
#[derive(Clone, Debug, PartialEq)]
pub struct ArmOperand {
    /// Vector Index for some vector operands
    pub vector_index: Option<u32>,

    /// Whether operand is subtracted
    pub subtracted: bool,

    pub shift: ArmShift,

    /// Operand type
    pub op_type: ArmOperandType,
}

/// ARM operand
#[derive(Clone, Debug, PartialEq)]
pub enum ArmOperandType {
    /// Register
    Reg(RegId),

    /// Immediate
    Imm(i32),

    /// Memory
    Mem(ArmOpMem),

    /// Floating point
    Fp(f64),

    /// C-IMM
    Cimm(i32),

    /// P-IMM
    Pimm(i32),

    /// SETEND instruction endianness
    Setend(ArmSetendType),

    /// Sysreg
    SysReg(RegId),

    /// Invalid
    Invalid,
}

/// ARM memory operand
#[derive(Debug, Copy, Clone)]
pub struct ArmOpMem(pub(crate) arm_op_mem);

impl<'a> ArmInsnDetail<'a> {
    /// Whether the instruction is a user mode
    pub fn usermode(&self) -> bool {
        self.0.usermode
    }

    /// Vector size
    pub fn vector_size(&self) -> i32 {
        self.0.vector_size as i32
    }

    /// Type of vector data
    pub fn vector_data(&self) -> ArmVectorData {
        self.0.vector_data
    }

    /// CPS mode for CPS instruction
    pub fn cps_mode(&self) -> ArmCPSMode {
        self.0.cps_mode
    }

    /// CPS flag for CPS instruction
    pub fn cps_flag(&self) -> ArmCPSFlag {
        self.0.cps_flag
    }

    /// Condition codes
    pub fn cc(&self) -> ArmCC {
        self.0.cc
    }

    /// Whether this insn updates flags
    pub fn update_flags(&self) -> bool {
        self.0.update_flags
    }

    /// Whether writeback is required
    pub fn writeback(&self) -> bool {
        self.0.writeback
    }

    /// Memory barrier
    pub fn mem_barrier(&self) -> ArmMemBarrier {
        self.0.mem_barrier
    }
}

impl_PartialEq_repr_fields!(ArmInsnDetail<'a> [ 'a ];
    usermode, vector_size, vector_data, cps_mode, cps_flag, cc, update_flags, writeback,
    mem_barrier, operands
);

impl ArmOpMem {
    /// Base register
    pub fn base(&self) -> RegId {
        RegId(self.0.base as RegIdInt)
    }

    /// Index value
    pub fn index(&self) -> RegId {
        RegId(self.0.index as RegIdInt)
    }

    /// Scale for index register (can be 1, or -1)
    pub fn scale(&self) -> i32 {
        self.0.scale as i32
    }

    /// Disp value
    pub fn disp(&self) -> i32 {
        self.0.disp as i32
    }
}

impl_PartialEq_repr_fields!(ArmOpMem;
    base, index, scale, disp
);

impl cmp::Eq for ArmOpMem {}

impl Default for ArmOperand {
    fn default() -> Self {
        ArmOperand {
            vector_index: None,
            subtracted: false,
            shift: ArmShift::Invalid,
            op_type: ArmOperandType::Invalid
        }
    }
}

impl<'a> From<&'a cs_arm_op> for ArmOperand {
    fn from(op: &cs_arm_op) -> ArmOperand {
        let shift = ArmShift::new(op.shift.type_, op.shift.value);
        let op_type = ArmOperandType::new(op.type_, op.__bindgen_anon_1);
        let vector_index = if op.vector_index >= 0 {
            Some(op.vector_index as u32)
        } else {
            None
        };
        ArmOperand {
            vector_index,
            shift,
            op_type,
            subtracted: op.subtracted,
        }
    }
}

def_arch_details_struct!(
    InsnDetail = ArmInsnDetail;
    Operand = ArmOperand;
    OperandIterator = ArmOperandIterator;
    OperandIteratorLife = ArmOperandIterator<'a>;
    [ pub struct ArmOperandIterator<'a>(slice::Iter<'a, cs_arm_op>); ]
    cs_arch_op = cs_arm_op;
    cs_arch = cs_arm;
);

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

    #[test]
    fn test_armshift() {
        use super::arm_shifter::*;
        use super::ArmShift::*;
        use std::os::raw::c_uint;

        fn t(shift_type_value: (arm_shifter, c_uint), arm_shift: ArmShift) {
            let (shift_type, value) = shift_type_value;
            assert_eq!(arm_shift, ArmShift::new(shift_type, value));
        }

        t((ARM_SFT_INVALID, 0), Invalid);
        t((ARM_SFT_ASR, 0), Asr(0));
        t((ARM_SFT_ASR_REG, 42), AsrReg(RegId(42)));
        t((ARM_SFT_RRX_REG, 42), RrxReg(RegId(42)));
    }

    #[test]
    fn test_arm_op_type() {
        use super::arm_op_type::*;
        use super::ArmOperandType::*;

        fn t(
            op_type_value: (arm_op_type, cs_arm_op__bindgen_ty_2),
            expected_op_type: ArmOperandType,
        ) {
            let (op_type, op_value) = op_type_value;
            let op_type = ArmOperandType::new(op_type, op_value);
            assert_eq!(expected_op_type, op_type);
        }

        t(
            (ARM_OP_INVALID, cs_arm_op__bindgen_ty_2 { reg: 0 }),
            Invalid,
        );
        t(
            (ARM_OP_REG, cs_arm_op__bindgen_ty_2 { reg: 0 }),
            Reg(RegId(0)),
        );
    }

    #[test]
    fn test_arm_insn_detail_eq() {
        let a1 = cs_arm {
            usermode: false,
            vector_size: 0,
            vector_data: arm_vectordata_type::ARM_VECTORDATA_INVALID,
            cps_mode: arm_cpsmode_type::ARM_CPSMODE_INVALID,
            cps_flag: arm_cpsflag_type::ARM_CPSFLAG_INVALID,
            cc: arm_cc::ARM_CC_INVALID,
            update_flags: false,
            writeback: false,
            mem_barrier: arm_mem_barrier::ARM_MB_INVALID,
            op_count: 0,
            operands: [
                cs_arm_op {
                    vector_index: 0,
                    shift: cs_arm_op__bindgen_ty_1 {
                        type_: arm_shifter::ARM_SFT_INVALID,
                        value: 0
                    },
                    type_: arm_op_type::ARM_OP_INVALID,
                    __bindgen_anon_1: cs_arm_op__bindgen_ty_2 { imm: 0 },
                    subtracted: false,
                }
            ; 36]
        };
        let a2 = cs_arm {
            usermode: true,
            ..a1
        };
        let a3 = cs_arm {
            op_count: 20,
            ..a1
        };
        let a4 = cs_arm {
            op_count: 19,
            ..a1
        };
        let a4_clone = a4.clone();
        assert_eq!(ArmInsnDetail(&a1), ArmInsnDetail(&a1));
        assert_ne!(ArmInsnDetail(&a1), ArmInsnDetail(&a2));
        assert_ne!(ArmInsnDetail(&a1), ArmInsnDetail(&a3));
        assert_ne!(ArmInsnDetail(&a3), ArmInsnDetail(&a4));
        assert_eq!(ArmInsnDetail(&a4), ArmInsnDetail(&a4_clone));
    }
}
<|endoftext|>


<commit_before>use cocoa::base::id;
use cocoa::foundation::NSString;
use metal_sys::{MTLArgument, MTLArgumentAccess, MTLArgumentType, MTLDataType};
use objc::runtime::YES;
use std::borrow::Cow;
use std::ffi::CStr;
use {FromRaw, StructType, TextureType};

pub struct Argument(id);

impl Argument {
    pub fn name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    pub fn access(&self) -> ArgumentAccess {
        unsafe { self.0.access().into() }
    }

    pub fn is_active(&self) -> bool {
        unsafe { self.0.active() == YES }
    }

    pub fn index(&self) -> usize {
        unsafe { self.0.index() as usize }
    }

    pub fn get_type(&self) -> ArgumentType {
        unsafe { self.0.getType().into() }
    }

    pub fn buffer_alignment(&self) -> Option<usize> {
        if self.get_type() == ArgumentType::Buffer {
            unsafe { Some(self.0.bufferAlignment() as usize) }
        } else {
            None
        }
    }

    pub fn buffer_data_size(&self) -> Option<usize> {
        if self.get_type() == ArgumentType::Buffer {
            unsafe { Some(self.0.bufferDataSize() as usize) }
        } else {
            None
        }
    }

    pub fn buffer_data_type(&self) -> Option<DataType> {
        if self.get_type() == ArgumentType::Buffer {
            unsafe { Some(self.0.bufferDataType().into()) }
        } else {
            None
        }
    }

    pub fn buffer_struct_type(&self) -> Option<StructType> {
        if self.get_type() == ArgumentType::Buffer {
            let struct_type = unsafe { self.0.bufferStructType() };
            StructType::from_raw(struct_type).ok()
        } else {
            None
        }
    }

    pub fn texture_data_type(&self) -> Option<DataType> {
        if self.get_type() == ArgumentType::Texture {
            unsafe { Some(self.0.textureDataType().into()) }
        } else {
            None
        }
    }

    pub fn texture_type(&self) -> Option<TextureType> {
        if self.get_type() == ArgumentType::Texture {
            unsafe { Some(self.0.textureType().into()) }
        } else {
            None
        }
    }

    pub fn threadgroup_memory_alignment(&self) -> Option<usize> {
        if self.get_type() == ArgumentType::ThreadgroupMemory {
            unsafe { Some(self.0.threadgroupMemoryAlignment() as usize) }
        } else {
            None
        }
    }

    pub fn threadgroup_memory_data_size(&self) -> Option<usize> {
        if self.get_type() == ArgumentType::ThreadgroupMemory {
            unsafe { Some(self.0.threadgroupMemoryDataSize() as usize) }
        } else {
            None
        }
    }
}

impl_from_into_raw!(Argument, of class "MTLArgument");

convertible_enum!{
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum ArgumentAccess : MTLArgumentAccess {
        ReadOnly => MTLArgumentAccessReadOnly,
        ReadWrite => MTLArgumentAccessReadWrite,
        WriteOnly => MTLArgumentAccessWriteOnly
    }
}

convertible_enum! {
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum ArgumentType : MTLArgumentType {
        Buffer => MTLArgumentTypeBuffer,
        ThreadgroupMemory => MTLArgumentTypeThreadgroupMemory,
        Texture => MTLArgumentTypeTexture,
        Sampler => MTLArgumentTypeSampler
    }
}

convertible_enum! {
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum DataType : MTLDataType {
        None => MTLDataTypeNone,
        Struct => MTLDataTypeStruct,
        Array => MTLDataTypeArray,

        Float => MTLDataTypeFloat,
        Float2 => MTLDataTypeFloat2,
        Float3 => MTLDataTypeFloat3,
        Float4 => MTLDataTypeFloat4,

        Float2x2 => MTLDataTypeFloat2x2,
        Float2x3 => MTLDataTypeFloat2x3,
        Float2x4 => MTLDataTypeFloat2x4,

        Float3x2 => MTLDataTypeFloat3x2,
        Float3x3 => MTLDataTypeFloat3x3,
        Float3x4 => MTLDataTypeFloat3x4,
        Float4x2 => MTLDataTypeFloat4x2,
        Float4x3 => MTLDataTypeFloat4x3,
        Float4x4 => MTLDataTypeFloat4x4,

        Half => MTLDataTypeHalf,
        Half2 => MTLDataTypeHalf2,
        Half3 => MTLDataTypeHalf3,
        Half4 => MTLDataTypeHalf4,

        Half2x2 => MTLDataTypeHalf2x2,
        Half2x3 => MTLDataTypeHalf2x3,
        Half2x4 => MTLDataTypeHalf2x4,

        Half3x2 => MTLDataTypeHalf3x2,
        Half3x3 => MTLDataTypeHalf3x3,
        Half3x4 => MTLDataTypeHalf3x4,

        Half4x2 => MTLDataTypeHalf4x2,
        Half4x3 => MTLDataTypeHalf4x3,
        Half4x4 => MTLDataTypeHalf4x4,

        Int => MTLDataTypeInt,
        Int2 => MTLDataTypeInt2,
        Int3 => MTLDataTypeInt3,
        Int4 => MTLDataTypeInt4,
        UInt => MTLDataTypeUInt,
        UInt2 => MTLDataTypeUInt2,
        UInt3 => MTLDataTypeUInt3,
        UInt4 => MTLDataTypeUInt4,

        Short => MTLDataTypeShort,
        Short2 => MTLDataTypeShort2,
        Short3 => MTLDataTypeShort3,
        Short4 => MTLDataTypeShort4,

        UShort => MTLDataTypeUShort,
        UShort2 => MTLDataTypeUShort2,
        UShort3 => MTLDataTypeUShort3,
        UShort4 => MTLDataTypeUShort4,

        Char => MTLDataTypeChar,
        Char2 => MTLDataTypeChar2,
        Char3 => MTLDataTypeChar3,
        Char4 => MTLDataTypeChar4,

        UChar => MTLDataTypeUChar,
        UChar2 => MTLDataTypeUChar2,
        UChar3 => MTLDataTypeUChar3,
        UChar4 => MTLDataTypeUChar4,

        Bool => MTLDataTypeBool,
        Bool2 => MTLDataTypeBool2,
        Bool3 => MTLDataTypeBool3,
        Bool4 => MTLDataTypeBool4
    }
}
<commit_msg>Fix Argument::name return type<commit_after>use cocoa::base::id;
use cocoa::foundation::NSString;
use metal_sys::{MTLArgument, MTLArgumentAccess, MTLArgumentType, MTLDataType};
use objc::runtime::YES;
use std::ffi::CStr;
use {FromRaw, StructType, TextureType};

pub struct Argument(id);

impl Argument {
    pub fn name(&self) -> &str {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_str().unwrap_or(&"") }
    }

    pub fn access(&self) -> ArgumentAccess {
        unsafe { self.0.access().into() }
    }

    pub fn is_active(&self) -> bool {
        unsafe { self.0.active() == YES }
    }

    pub fn index(&self) -> usize {
        unsafe { self.0.index() as usize }
    }

    pub fn get_type(&self) -> ArgumentType {
        unsafe { self.0.getType().into() }
    }

    pub fn buffer_alignment(&self) -> Option<usize> {
        if self.get_type() == ArgumentType::Buffer {
            unsafe { Some(self.0.bufferAlignment() as usize) }
        } else {
            None
        }
    }

    pub fn buffer_data_size(&self) -> Option<usize> {
        if self.get_type() == ArgumentType::Buffer {
            unsafe { Some(self.0.bufferDataSize() as usize) }
        } else {
            None
        }
    }

    pub fn buffer_data_type(&self) -> Option<DataType> {
        if self.get_type() == ArgumentType::Buffer {
            unsafe { Some(self.0.bufferDataType().into()) }
        } else {
            None
        }
    }

    pub fn buffer_struct_type(&self) -> Option<StructType> {
        if self.get_type() == ArgumentType::Buffer {
            let struct_type = unsafe { self.0.bufferStructType() };
            StructType::from_raw(struct_type).ok()
        } else {
            None
        }
    }

    pub fn texture_data_type(&self) -> Option<DataType> {
        if self.get_type() == ArgumentType::Texture {
            unsafe { Some(self.0.textureDataType().into()) }
        } else {
            None
        }
    }

    pub fn texture_type(&self) -> Option<TextureType> {
        if self.get_type() == ArgumentType::Texture {
            unsafe { Some(self.0.textureType().into()) }
        } else {
            None
        }
    }

    pub fn threadgroup_memory_alignment(&self) -> Option<usize> {
        if self.get_type() == ArgumentType::ThreadgroupMemory {
            unsafe { Some(self.0.threadgroupMemoryAlignment() as usize) }
        } else {
            None
        }
    }

    pub fn threadgroup_memory_data_size(&self) -> Option<usize> {
        if self.get_type() == ArgumentType::ThreadgroupMemory {
            unsafe { Some(self.0.threadgroupMemoryDataSize() as usize) }
        } else {
            None
        }
    }
}

impl_from_into_raw!(Argument, of class "MTLArgument");

convertible_enum!{
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum ArgumentAccess : MTLArgumentAccess {
        ReadOnly => MTLArgumentAccessReadOnly,
        ReadWrite => MTLArgumentAccessReadWrite,
        WriteOnly => MTLArgumentAccessWriteOnly
    }
}

convertible_enum! {
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum ArgumentType : MTLArgumentType {
        Buffer => MTLArgumentTypeBuffer,
        ThreadgroupMemory => MTLArgumentTypeThreadgroupMemory,
        Texture => MTLArgumentTypeTexture,
        Sampler => MTLArgumentTypeSampler
    }
}

convertible_enum! {
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    pub enum DataType : MTLDataType {
        None => MTLDataTypeNone,
        Struct => MTLDataTypeStruct,
        Array => MTLDataTypeArray,

        Float => MTLDataTypeFloat,
        Float2 => MTLDataTypeFloat2,
        Float3 => MTLDataTypeFloat3,
        Float4 => MTLDataTypeFloat4,

        Float2x2 => MTLDataTypeFloat2x2,
        Float2x3 => MTLDataTypeFloat2x3,
        Float2x4 => MTLDataTypeFloat2x4,

        Float3x2 => MTLDataTypeFloat3x2,
        Float3x3 => MTLDataTypeFloat3x3,
        Float3x4 => MTLDataTypeFloat3x4,
        Float4x2 => MTLDataTypeFloat4x2,
        Float4x3 => MTLDataTypeFloat4x3,
        Float4x4 => MTLDataTypeFloat4x4,

        Half => MTLDataTypeHalf,
        Half2 => MTLDataTypeHalf2,
        Half3 => MTLDataTypeHalf3,
        Half4 => MTLDataTypeHalf4,

        Half2x2 => MTLDataTypeHalf2x2,
        Half2x3 => MTLDataTypeHalf2x3,
        Half2x4 => MTLDataTypeHalf2x4,

        Half3x2 => MTLDataTypeHalf3x2,
        Half3x3 => MTLDataTypeHalf3x3,
        Half3x4 => MTLDataTypeHalf3x4,

        Half4x2 => MTLDataTypeHalf4x2,
        Half4x3 => MTLDataTypeHalf4x3,
        Half4x4 => MTLDataTypeHalf4x4,

        Int => MTLDataTypeInt,
        Int2 => MTLDataTypeInt2,
        Int3 => MTLDataTypeInt3,
        Int4 => MTLDataTypeInt4,
        UInt => MTLDataTypeUInt,
        UInt2 => MTLDataTypeUInt2,
        UInt3 => MTLDataTypeUInt3,
        UInt4 => MTLDataTypeUInt4,

        Short => MTLDataTypeShort,
        Short2 => MTLDataTypeShort2,
        Short3 => MTLDataTypeShort3,
        Short4 => MTLDataTypeShort4,

        UShort => MTLDataTypeUShort,
        UShort2 => MTLDataTypeUShort2,
        UShort3 => MTLDataTypeUShort3,
        UShort4 => MTLDataTypeUShort4,

        Char => MTLDataTypeChar,
        Char2 => MTLDataTypeChar2,
        Char3 => MTLDataTypeChar3,
        Char4 => MTLDataTypeChar4,

        UChar => MTLDataTypeUChar,
        UChar2 => MTLDataTypeUChar2,
        UChar3 => MTLDataTypeUChar3,
        UChar4 => MTLDataTypeUChar4,

        Bool => MTLDataTypeBool,
        Bool2 => MTLDataTypeBool2,
        Bool3 => MTLDataTypeBool3,
        Bool4 => MTLDataTypeBool4
    }
}
<|endoftext|>


<commit_before>use template::RdxSortTemplate;

// same as u32
impl RdxSortTemplate for char {
    fn cfg_nbuckets() -> usize {
        16
    }

    fn cfg_nrounds() -> usize {
        8
    }

    fn get_bucket(&self, round: usize) -> usize {
        let shift = round << 2;
        (((*self as u32) >> shift) & 15u32) as usize
    }
}
<commit_msg>make char using the u32 implementation<commit_after>use template::RdxSortTemplate;

impl RdxSortTemplate for char {
    fn cfg_nbuckets() -> usize {
        <u32 as RdxSortTemplate>::cfg_nbuckets()
    }

    fn cfg_nrounds() -> usize {
        <u32 as RdxSortTemplate>::cfg_nrounds()
    }

    fn get_bucket(&self, round: usize) -> usize {
        (*self as u32).get_bucket(round)
    }
}
<|endoftext|>


<commit_before>//! # `concurrent` — An efficient concurrent reclamation system
//!
//! `concurrent` builds upon hazard pointers to create a extremely performant system for
//! concurrently handling memory. It is more general and convinient — and often also faster — than
//! epoch-based reclamation.
//!
//! ## Why?
//!
//! aturon's [blog post](https://aturon.github.io/blog/2015/08/27/epoch/) explains the issues of
//! concurrent memory handling very well, although it take basis in epoch-based reclamation, which
//! this crate is an alternative for.
//!
//! The gist essentially is that you need to delete objects in most concurrent data structure
//! (otherwise there would be memory leaks), however cannot safely do so, as there is no way to
//! know if another thread is accessing the object in question. This (and other reclamation
//! systems) provides a solution to this problem.
//!
//! ## Usage
//!
//! While the low-level API is available, it is generally sufficient to use the `concurrent::Cell`
//! abstraction. This acts much like familiar Rust APIs. It allows the programmer to concurrently
//! access a value through references, as well as update it, and more. Refer to the respective docs
//! for more information.
//!
//! ## Why not crossbeam/epochs?
//!
//! Epoch-based reclamation has some unfortunate issues. It cannot work properly if an epoch is
//! constantly active. It assumes that at some point, the thread reads no objects, which is true in
//! some cases, but not always. This makes it unsuitable for many thing, such as event loops and
//! more.
//!
//! Futhermore, to end an epoch, the system must do some relatively expensive operations, whereas
//! `concurrent` (and most hazard pointer implementations) need not to do this, as it can reuse
//! the "epochs" (in this case "hazards") later.
//!
//! While I have no benchmarks yet, the tests I've made (on skiplists and other structures)
//! generally shows that `concurrent` outperforms `crossbeam` in most cases.
//!
//! ## Internals
//!
//! It based on hazard pointers, although there are several differences. The idea is essentially
//! that the system keeps track of some number of "hazards". As long as a hazard protects some
//! object, the object cannot be deleted.
//!
//! Once in a while, a thread performs a garbage collection by scanning the hazards and finding the
//! objects not currently protected by any hazard. These objects are then deleted.
//!
//! To improve performance, we use a layered approach: Both garbage (objects to be deleted
//! eventually) and hazards are cached thread locally. This reduces the amount of atomic operations
//! and cache misses.
//!
//! ## Garbage collection
//!
//! Garbage collection of the concurrently managed object is done automatically between every `n`
//! frees where `n` is chosen from some probability distribution.
//!
//! Note that a garbage collection cycle might not clear all objects. For example, some objects
//! could be protected by hazards. Others might not have been exported from the thread-local cache
//! yet.

#[macro_use]
extern crate lazy_static;
extern crate parking_lot;
extern crate rand;

mod cell;
mod garbage;
mod global;
mod guard;
mod hazard;
mod local;
mod mpsc;

pub use cell::Cell;
pub use guard::Guard;

use std::mem;
use garbage::Garbage;

/// Collect garbage.
///
/// This function does two things:
///
/// 1. Export garbage from current thread to the global queue.
/// 2. Collect all the garbage and run destructors on the unused items.
///
/// If another thread is currently doing 2., it will be skipped.
///
/// # Use case
///
/// Note that it is not necessary to call this manually, it will do so automatically after some
/// time has passed.
///
/// However, it can be nice if you have just trashed a very memory-hungy item in the current
/// thread, and want to attempt to GC it.
///
/// # Other threads
///
/// This cannot collect un-propagated garbage accumulated locally in other threads. This will only
/// attempt to collect the accumulated local and global (propagated) garbage.
pub fn gc() {
    // Export the local garbage to ensure that the garbage of the current thread gets collected.
    local::export_garbage();
    // Run the global GC.
    global::gc();
}

/// Declare a pointer unreachable garbage to be deleted eventually.
///
/// This adds `ptr` to the queue of garbage, which eventually will be destroyed through its
/// destructor given in `dtor`. This is ensured to happen at some point _after_ the last guard
/// protecting the pointer is dropped.
///
/// It is legal for `ptr` to be invalidated by `dtor`, such that accessing it is undefined after
/// `dtor` has been run. This means that `dtor` can safely (there are exceptions, see below) run a
/// destructor of `ptr`'s data.
///
/// # Unreachability criterion
///
/// If you invalidate `ptr` in the destructor, it is extremely important that `ptr` is no longer
/// reachable from any data structure: It should be impossible to create _new_ guard representing
/// `ptr` from now on, as such thing can mean that new guards can be created after it is dropped
/// causing use-after-free.
pub fn add_garbage<T>(ptr: &'static T, dtor: fn(&'static T)) {
    local::add_garbage(unsafe {
        Garbage::new(ptr as *const T as *const u8 as *mut u8, mem::transmute(dtor))
    });
}
<commit_msg>Fix notes about performance of `concurrent`.<commit_after>//! # `concurrent` — An efficient concurrent reclamation system
//!
//! `concurrent` builds upon hazard pointers to create a extremely performant system for
//! concurrently handling memory. It is more general and convinient — and often also faster — than
//! epoch-based reclamation.
//!
//! ## Why?
//!
//! aturon's [blog post](https://aturon.github.io/blog/2015/08/27/epoch/) explains the issues of
//! concurrent memory handling very well, although it take basis in epoch-based reclamation, which
//! this crate is an alternative for.
//!
//! The gist essentially is that you need to delete objects in most concurrent data structure
//! (otherwise there would be memory leaks), however cannot safely do so, as there is no way to
//! know if another thread is accessing the object in question. This (and other reclamation
//! systems) provides a solution to this problem.
//!
//! ## Usage
//!
//! While the low-level API is available, it is generally sufficient to use the `concurrent::Cell`
//! abstraction. This acts much like familiar Rust APIs. It allows the programmer to concurrently
//! access a value through references, as well as update it, and more. Refer to the respective docs
//! for more information.
//!
//! ## Why not crossbeam/epochs?
//!
//! Epochs and classical hazard pointers are generally faster than this crate, but it doesn't
//! matter how fast it is, it has to be right.
//!
//! The issue with most other and faster solutions is that, if there is a non-trivial amount of
//! threads (say 16) constantly reading/storing some pointer, it will never get to a state, where
//! it can be reclaimed.
//!
//! In other words, given sufficient amount of threads and frequency, the gaps between the
//! reclamation might be very very long, causing very high memory usage, and potentially OOM
//! crashes.
//!
//! These issues are not hypothethical. It happened to me while testing the caching system of TFS.
//! Essentially, the to-be-destroyed garbage accumulated several gigabytes, without ever being open
//! to a collection cycle.
//!
//! It reminds of the MongoDB debate. It might very well be the fastest solution¹, but if it can't
//! even ensure consistency, what is the point?
//!
//! That being said, there are cases where this library is faster than the alternatives.
//! Moreover, there are cases where the other libraries are fine (e.g. if you have a bounded number
//! of thread and a medium-long interval between accesses).
//!
//! ¹If you want a super fast memory reclamation system, you should try NOP™, and not calling
//!  destructors.
//!
//! ## Internals
//!
//! It based on hazard pointers, although there are several differences. The idea is essentially
//! that the system keeps track of some number of "hazards". As long as a hazard protects some
//! object, the object cannot be deleted.
//!
//! Once in a while, a thread performs a garbage collection by scanning the hazards and finding the
//! objects not currently protected by any hazard. These objects are then deleted.
//!
//! To improve performance, we use a layered approach: Both garbage (objects to be deleted
//! eventually) and hazards are cached thread locally. This reduces the amount of atomic operations
//! and cache misses.
//!
//! ## Garbage collection
//!
//! Garbage collection of the concurrently managed object is done automatically between every `n`
//! frees where `n` is chosen from some probability distribution.
//!
//! Note that a garbage collection cycle might not clear all objects. For example, some objects
//! could be protected by hazards. Others might not have been exported from the thread-local cache
//! yet.
//!
//! ## Performance
//!
//! It is worth noting that atomic reads through this library usually requires three atomic CPU
//! instruction, this means that if you are traversing a list or something like that, this library
//! might not be for you.

#[macro_use]
extern crate lazy_static;
extern crate parking_lot;
extern crate rand;

mod cell;
mod garbage;
mod global;
mod guard;
mod hazard;
mod local;
mod mpsc;

pub use cell::Cell;
pub use guard::Guard;

use std::mem;
use garbage::Garbage;

/// Collect garbage.
///
/// This function does two things:
///
/// 1. Export garbage from current thread to the global queue.
/// 2. Collect all the garbage and run destructors on the unused items.
///
/// If another thread is currently doing 2., it will be skipped.
///
/// # Use case
///
/// Note that it is not necessary to call this manually, it will do so automatically after some
/// time has passed.
///
/// However, it can be nice if you have just trashed a very memory-hungy item in the current
/// thread, and want to attempt to GC it.
///
/// # Other threads
///
/// This cannot collect un-propagated garbage accumulated locally in other threads. This will only
/// attempt to collect the accumulated local and global (propagated) garbage.
pub fn gc() {
    // Export the local garbage to ensure that the garbage of the current thread gets collected.
    local::export_garbage();
    // Run the global GC.
    global::gc();
}

/// Declare a pointer unreachable garbage to be deleted eventually.
///
/// This adds `ptr` to the queue of garbage, which eventually will be destroyed through its
/// destructor given in `dtor`. This is ensured to happen at some point _after_ the last guard
/// protecting the pointer is dropped.
///
/// It is legal for `ptr` to be invalidated by `dtor`, such that accessing it is undefined after
/// `dtor` has been run. This means that `dtor` can safely (there are exceptions, see below) run a
/// destructor of `ptr`'s data.
///
/// # Unreachability criterion
///
/// If you invalidate `ptr` in the destructor, it is extremely important that `ptr` is no longer
/// reachable from any data structure: It should be impossible to create _new_ guard representing
/// `ptr` from now on, as such thing can mean that new guards can be created after it is dropped
/// causing use-after-free.
pub fn add_garbage<T>(ptr: &'static T, dtor: fn(&'static T)) {
    local::add_garbage(unsafe {
        Garbage::new(ptr as *const T as *const u8 as *mut u8, mem::transmute(dtor))
    });
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use ast::{Program, Statement, Expression, Type};

pub fn eval_program(p: &Program) {
  let Program(ref top) = *p;
  let ctx = Context::new();
  ctx.eval(top);
}

struct Context {
  symbol_value: HashMap<String, Expression>,
  symbol_types: HashMap<String, Type>
}

impl Context {
  fn new() -> Context {
    Context {
      symbol_value: HashMap::new(),
      symbol_types: HashMap::new()
    }
  }

  fn get(&self, s: &String) -> &Expression {
    match self.symbol_value.get(s) {
      Some(i) => i,
      None => panic!("Identifier '{}' is not defined", s)
    }
  }

  fn eval(&mut self, s: &Statement) {
    match *s {
      Statement::Block(ref c) => for s in c.iter() { self.eval(s); },
      Statement::Declare(ref t, ref ident, ref expr) => self.declare(t, ident, expr),
      Statement::Assign(ref ident, ref expr) => self.assign(ident, expr),
      Statement::Print(ref s) => println!("{} = {}", s, self.get(s))
    }
  }

  fn declare(&mut self, t: &Type, ident: &String, expr: &Expression) {
    self.symbol_types.insert(ident.clone(), t.clone());
    self.assign(ident, expr);
  }

  fn assign(&mut self, ident: &String, expr: &Expression) {
    let evaluated_expr = self.eval_expression(expr);
    self.symbol_value.insert(ident.clone(), evaluated_expr);
  }

  fn eval_expression(&self, expr: &Expression) -> Expression {
    expr.clone()
  }
}

<commit_msg>Ensure that ast::eval::Context is mutable<commit_after>use std::collections::HashMap;
use ast::{Program, Statement, Expression, Type};

pub fn eval_program(p: &Program) {
  let Program(ref top) = *p;
  let mut ctx = Context::new();
  ctx.eval(top);
}

struct Context {
  symbol_value: HashMap<String, Expression>,
  symbol_types: HashMap<String, Type>
}

impl Context {
  fn new() -> Context {
    Context {
      symbol_value: HashMap::new(),
      symbol_types: HashMap::new()
    }
  }

  fn get(&self, s: &String) -> &Expression {
    match self.symbol_value.get(s) {
      Some(i) => i,
      None => panic!("Identifier '{}' is not defined", s)
    }
  }

  fn eval(&mut self, s: &Statement) {
    match *s {
      Statement::Block(ref c) => for s in c.iter() { self.eval(s); },
      Statement::Declare(ref t, ref ident, ref expr) => self.declare(t, ident, expr),
      Statement::Assign(ref ident, ref expr) => self.assign(ident, expr),
      Statement::Print(ref s) => println!("{} = {}", s, self.get(s))
    }
  }

  fn declare(&mut self, t: &Type, ident: &String, expr: &Expression) {
    self.symbol_types.insert(ident.clone(), t.clone());
    self.assign(ident, expr);
  }

  fn assign(&mut self, ident: &String, expr: &Expression) {
    let evaluated_expr = self.eval_expression(expr);
    self.symbol_value.insert(ident.clone(), evaluated_expr);
  }

  fn eval_expression(&self, expr: &Expression) -> Expression {
    expr.clone()
  }
}

<|endoftext|>


<commit_before>use std::iter::Peekable;
use std::str::FromStr;
use std::time::Duration;

use game::{Position, FromTo, White, Black, fen_to_position, NumPlies, NumMoves};
use super::types::{CmdVal, RegisterParam, GoParam};
use super::types::options;
use types::NumNodes;

pub fn parse(s: &str) -> Option<CmdVal> {
    let mut words = s.words().peekable();

    let mut cmd_val: Option<CmdVal> = None;

    while cmd_val.is_none() {
        let next_word_opt = words.next();
        let next_word = match next_word_opt {
            Some(val) => val,
            None => break,
        };

        cmd_val = match next_word {
            "uci" => Some(CmdVal::Uci),
            "debug" => parse_on_off(&mut words).map(|val| CmdVal::Debug(val)),
            "isready" => Some(CmdVal::IsReady),
            "setoption" => parse_option_val(&mut words).map(|(name, val)| CmdVal::SetOption(name, val)),
            "register" => parse_register_vec(&mut words).map(|val| CmdVal::Register(val)),
            "ucinewgame" => Some(CmdVal::UciNewGame),
            "position" => {
                let pos_opt = parse_position(&mut words);
                match parse_move_vec(&mut words) {
                    Some(moves) => Some(CmdVal::SetupPosition(pos_opt, moves)),
                    None => None,
                }
            },
            "go" => parse_go_param_vec(&mut words).map(|val| CmdVal::Go(val)),
            "stop" => Some(CmdVal::Stop),
            "ponderhit" => Some(CmdVal::PonderHit),
            "quit" => Some(CmdVal::Quit),
            _ => None,
        }
    }

    cmd_val
}

fn parse_on_off(words: &mut Iterator<&str>) -> Option<bool> {
    let mut ans = None;
    while ans.is_none() {
        let next_word_opt = words.next();
        let next_word = match next_word_opt {
            Some(val) => val,
            None => break,
        };
        ans = match next_word {
            "on" => Some(true),
            "off" => Some(false),
            _ => None,
        }
    }
    ans
}

fn parse_option_val<'a,T>(words: &mut T) -> Option<options::NameAndVal>
where T: Iterator<&'a str> {
    // TODO parse options.
    Some((options::Name::Dummy, options::Val::Spin(1)))
}

fn parse_register_vec<'a,T>(words: &mut Peekable<&'a str,T>) -> Option<Vec<RegisterParam>>
where T: Iterator<&'a str> {
    let mut res = Vec::<RegisterParam>::new();
    while let Some(next_word) = words.next() {
        let register_val = match next_word {
            "later" => Some(RegisterParam::Later),
            "name" => {
                let mut name_vec = Vec::<&str>::new();
                loop {
                    let curr_name = words.peek().and_then( |s| {
                        if ["late","name","code"].contains(s) { None }
                        else { Some(*s) }
                    });
                    match curr_name {
                        Some(val) => {
                            name_vec.push(val);
                            words.next();
                        },
                        None => break,
                    }
                }
                Some(RegisterParam::Name(name_vec.connect(" ")))
            },
            "code" => words.next().map( |x| RegisterParam::Code(x.to_string())),
            _ => None,
        };
        if let Some(val) = register_val {
            res.push(val);
        }
    }
    if res.is_empty() { None } else { Some(res) }
}

fn parse_position<'a,T>(words: &mut T) -> Option<Position>
where T: Iterator<&'a str> {
    let six_words: Vec<_> = words.by_ref().take(6).collect();
    fen_to_position(&*six_words.connect(" ")).ok()
}

fn parse_move_vec<'a,T>(words: &mut Peekable<&'a str,T>) -> Option<Vec<FromTo>>
where T: Iterator<&'a str> {
    let mut res = Vec::<FromTo>::new();
    while let Some(val) = words.peek().and_then(|val| FromStr::from_str(*val)) {
        res.push(val);
        words.next();
    }
    if res.is_empty() { None } else { Some(res) }
}

fn parse_go_param_vec<'a,T>(words: &mut Peekable<&'a str,T>) -> Option<Vec<GoParam>>
where T: Iterator<&'a str> {
    let mut res = Vec::<GoParam>::new();
    while let Some(next_word) = words.next() {
        match next_word {
            "search moves" => parse_move_vec(words).map(|x| GoParam::SearchMoves(x)),
            "ponder" => Some(GoParam::Ponder),
            "wtime"     => words.next().and_then(|s| s.parse::<i64>())
                                       .map(|x| GoParam::Time(White,Duration::milliseconds(x))),
            "btime"     => words.next().and_then(|s| s.parse::<i64>())
                                       .map(|x| GoParam::Time(Black,Duration::milliseconds(x))),
            "winc"      => words.next().and_then(|s| s.parse::<i64>())
                                       .map(|x| GoParam::IncTime(White,Duration::milliseconds(x))),
            "binc"      => words.next().and_then(|s| s.parse::<i64>())
                                       .map(|x| GoParam::IncTime(Black,Duration::milliseconds(x))),
            "movestogo" => words.next().and_then(|s| s.parse::<u16>())
                                       .map(|x| GoParam::MovesToGo(NumMoves(x))),
            "depth"     => words.next().and_then(|s| s.parse::<u16>())
                                       .map(|x| GoParam::Depth(NumPlies(x))),
            "nodes"     => words.next().and_then(|s| s.parse::<u64>())
                                       .map(|x| GoParam::Nodes(NumNodes(x))),
            "mate"      => words.next().and_then(|s| s.parse::<u16>())
                                       .map(|x| GoParam::Mate(NumMoves(x))),
            "movetime"  => words.next().and_then(|s| s.parse::<i64>())
                                       .map(|x| GoParam::MoveTime(Duration::milliseconds(x))),
            "infinite" => Some(GoParam::Infinite),
            _ => None,
        }.map(|val| res.push(val));
    }
    if res.is_empty() { None } else { Some(res) }
}
<commit_msg>Fix parse_position() to support "startpos" and parse errors.<commit_after>use std::iter::Peekable;
use std::str::FromStr;
use std::time::Duration;

use game::{Position, FromTo, White, Black, fen_to_position, start_pos, NumPlies, NumMoves};
use super::types::{CmdVal, RegisterParam, GoParam};
use super::types::options;
use types::NumNodes;

pub fn parse(s: &str) -> Option<CmdVal> {
    let mut words = s.words().peekable();

    let mut cmd_val: Option<CmdVal> = None;

    while cmd_val.is_none() {
        let next_word_opt = words.next();
        let next_word = match next_word_opt {
            Some(val) => val,
            None => break,
        };

        cmd_val = match next_word {
            "uci" => Some(CmdVal::Uci),
            "debug" => parse_on_off(&mut words).map(|val| CmdVal::Debug(val)),
            "isready" => Some(CmdVal::IsReady),
            "setoption" => parse_option_val(&mut words).map(|(name, val)| CmdVal::SetOption(name, val)),
            "register" => parse_register_vec(&mut words).map(|val| CmdVal::Register(val)),
            "ucinewgame" => Some(CmdVal::UciNewGame),
            "position" => {
                let pos_opt = parse_position(&mut words);
                match parse_move_vec(&mut words) {
                    Some(moves) => Some(CmdVal::SetupPosition(pos_opt, moves)),
                    None => None,
                }
            },
            "go" => parse_go_param_vec(&mut words).map(|val| CmdVal::Go(val)),
            "stop" => Some(CmdVal::Stop),
            "ponderhit" => Some(CmdVal::PonderHit),
            "quit" => Some(CmdVal::Quit),
            _ => None,
        }
    }

    cmd_val
}

fn parse_on_off(words: &mut Iterator<&str>) -> Option<bool> {
    let mut ans = None;
    while ans.is_none() {
        let next_word_opt = words.next();
        let next_word = match next_word_opt {
            Some(val) => val,
            None => break,
        };
        ans = match next_word {
            "on" => Some(true),
            "off" => Some(false),
            _ => None,
        }
    }
    ans
}

fn parse_option_val<'a,T>(words: &mut T) -> Option<options::NameAndVal>
where T: Iterator<&'a str> {
    // TODO parse options.
    Some((options::Name::Dummy, options::Val::Spin(1)))
}

fn parse_register_vec<'a,T>(words: &mut Peekable<&'a str,T>) -> Option<Vec<RegisterParam>>
where T: Iterator<&'a str> {
    let mut res = Vec::<RegisterParam>::new();
    while let Some(next_word) = words.next() {
        let register_val = match next_word {
            "later" => Some(RegisterParam::Later),
            "name" => {
                let mut name_vec = Vec::<&str>::new();
                loop {
                    let curr_name = words.peek().and_then( |s| {
                        if ["late","name","code"].contains(s) { None }
                        else { Some(*s) }
                    });
                    match curr_name {
                        Some(val) => {
                            name_vec.push(val);
                            words.next();
                        },
                        None => break,
                    }
                }
                Some(RegisterParam::Name(name_vec.connect(" ")))
            },
            "code" => words.next().map( |x| RegisterParam::Code(x.to_string())),
            _ => None,
        };
        if let Some(val) = register_val {
            res.push(val);
        }
    }
    if res.is_empty() { None } else { Some(res) }
}

fn parse_position<'a,T>(words: &mut Peekable<&'a str,T>) -> Option<Position>
where T: Iterator<&'a str> {
    if words.peek() == Some(&"startpos") {
        words.next();
        return Some(start_pos());
    }
    let six_words: Vec<_> = words.by_ref().take(6).collect();
    fen_to_position(&*six_words.connect(" ")).ok()
}

fn parse_move_vec<'a,T>(words: &mut Peekable<&'a str,T>) -> Option<Vec<FromTo>>
where T: Iterator<&'a str> {
    let mut res = Vec::<FromTo>::new();
    while let Some(val) = words.peek().and_then(|val| FromStr::from_str(*val)) {
        res.push(val);
        words.next();
    }
    if res.is_empty() { None } else { Some(res) }
}

fn parse_go_param_vec<'a,T>(words: &mut Peekable<&'a str,T>) -> Option<Vec<GoParam>>
where T: Iterator<&'a str> {
    let mut res = Vec::<GoParam>::new();
    while let Some(next_word) = words.next() {
        match next_word {
            "search moves" => parse_move_vec(words).map(|x| GoParam::SearchMoves(x)),
            "ponder" => Some(GoParam::Ponder),
            "wtime"     => words.next().and_then(|s| s.parse::<i64>())
                                       .map(|x| GoParam::Time(White,Duration::milliseconds(x))),
            "btime"     => words.next().and_then(|s| s.parse::<i64>())
                                       .map(|x| GoParam::Time(Black,Duration::milliseconds(x))),
            "winc"      => words.next().and_then(|s| s.parse::<i64>())
                                       .map(|x| GoParam::IncTime(White,Duration::milliseconds(x))),
            "binc"      => words.next().and_then(|s| s.parse::<i64>())
                                       .map(|x| GoParam::IncTime(Black,Duration::milliseconds(x))),
            "movestogo" => words.next().and_then(|s| s.parse::<u16>())
                                       .map(|x| GoParam::MovesToGo(NumMoves(x))),
            "depth"     => words.next().and_then(|s| s.parse::<u16>())
                                       .map(|x| GoParam::Depth(NumPlies(x))),
            "nodes"     => words.next().and_then(|s| s.parse::<u64>())
                                       .map(|x| GoParam::Nodes(NumNodes(x))),
            "mate"      => words.next().and_then(|s| s.parse::<u16>())
                                       .map(|x| GoParam::Mate(NumMoves(x))),
            "movetime"  => words.next().and_then(|s| s.parse::<i64>())
                                       .map(|x| GoParam::MoveTime(Duration::milliseconds(x))),
            "infinite" => Some(GoParam::Infinite),
            _ => None,
        }.map(|val| res.push(val));
    }
    if res.is_empty() { None } else { Some(res) }
}
<|endoftext|>


<commit_before>use core::num::{Zero, One};
use numeric::*;

use std::cmp::FuzzyEq;

use mat::{Mat4, BaseMat4};

/**
 * Create a perspective projection matrix
 *
 * Note: the fovy parameter should be specified in degrees.
 *
 * This is the equivalent of the gluPerspective function, the algorithm of which
 * can be found [here](http://www.opengl.org/wiki/GluPerspective_code).
 */
#[inline(always)]
pub fn perspective<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(fovy: T, aspectRatio: T, near: T, far: T) -> Mat4<T> {
    let _2: T = num::cast(2);

    let ymax = near * tan(radians(fovy / _2));
    let xmax = ymax * aspectRatio;

    frustum(-xmax, xmax, -ymax, ymax, near, far)
}

/**
 * Define a view frustrum
 *
 * This is the equivalent of the now deprecated [glFrustrum]
 * (http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml) function.
 */
#[inline(always)]
pub fn frustum<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Mat4<T> {
    let _0: T = num::cast(0);
    let _1: T = num::cast(1);
    let _2: T = num::cast(2);

    let c0r0 = (_2 * near) / (right - left);
    let c0r1 = _0;
    let c0r2 = _0;
    let c0r3 = _0;

    let c1r0 = _0;
    let c1r1 = (_2 * near) / (top - bottom);
    let c1r2 = _0;
    let c1r3 = _0;

    let c2r0 = (right + left) / (right - left);
    let c2r1 = (top + bottom) / (top - bottom);
    let c2r2 = -(far + near) / (far - near);
    let c2r3 = -_1;

    let c3r0 = _0;
    let c3r1 = _0;
    let c3r2 = -(_2 * far * near) / (far - near);
    let c3r3 = _0;

    BaseMat4::new(c0r0, c0r1, c0r2, c0r3,
                  c1r0, c1r1, c1r2, c1r3,
                  c2r0, c2r1, c2r2, c2r3,
                  c3r0, c3r1, c3r2, c3r3)
}

/**
 * Create an orthographic projection matrix
 *
 * This is the equivalent of the now deprecated [glOrtho]
 * (http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml) function.
 */
#[inline(always)]
pub fn orthographic<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Mat4<T> {
    let _0: T = num::cast(0);
    let _1: T = num::cast(1);
    let _2: T = num::cast(2);

    BaseMat4::new(_2 / (right - left), _0, _0, _0,
                  _0, _2 / (top - bottom), _0, _0,
                  _0, _0, -_2 / (far - near), _0,
                  -(right + left) / (right - left), -(top + bottom) / (top - bottom),
                    -(far + near) / (far - near), _1)
}
<commit_msg>Clean up 'orthographic' function and rename to 'ortho'<commit_after>use core::num::{Zero, One};
use numeric::*;

use std::cmp::FuzzyEq;

use mat::{Mat4, BaseMat4};

/**
 * Create a perspective projection matrix
 *
 * Note: the fovy parameter should be specified in degrees.
 *
 * This is the equivalent of the gluPerspective function, the algorithm of which
 * can be found [here](http://www.opengl.org/wiki/GluPerspective_code).
 */
#[inline(always)]
pub fn perspective<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(fovy: T, aspectRatio: T, near: T, far: T) -> Mat4<T> {
    let _2: T = num::cast(2);

    let ymax = near * tan(radians(fovy / _2));
    let xmax = ymax * aspectRatio;

    frustum(-xmax, xmax, -ymax, ymax, near, far)
}

/**
 * Define a view frustrum
 *
 * This is the equivalent of the now deprecated [glFrustrum]
 * (http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml) function.
 */
#[inline(always)]
pub fn frustum<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Mat4<T> {
    let _0: T = num::cast(0);
    let _1: T = num::cast(1);
    let _2: T = num::cast(2);

    let c0r0 = (_2 * near) / (right - left);
    let c0r1 = _0;
    let c0r2 = _0;
    let c0r3 = _0;

    let c1r0 = _0;
    let c1r1 = (_2 * near) / (top - bottom);
    let c1r2 = _0;
    let c1r3 = _0;

    let c2r0 = (right + left) / (right - left);
    let c2r1 = (top + bottom) / (top - bottom);
    let c2r2 = -(far + near) / (far - near);
    let c2r3 = -_1;

    let c3r0 = _0;
    let c3r1 = _0;
    let c3r2 = -(_2 * far * near) / (far - near);
    let c3r3 = _0;

    BaseMat4::new(c0r0, c0r1, c0r2, c0r3,
                  c1r0, c1r1, c1r2, c1r3,
                  c2r0, c2r1, c2r2, c2r3,
                  c3r0, c3r1, c3r2, c3r3)
}

/**
 * Create an orthographic projection matrix
 *
 * This is the equivalent of the now deprecated [glOrtho]
 * (http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml) function.
 */
#[inline(always)]
pub fn ortho<T:Copy + Float + Zero + One + FuzzyEq<T> + Add<T,T> + Sub<T,T> + Mul<T,T> + Div<T,T> + Neg<T>>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Mat4<T> {
    let _0: T = num::cast(0);
    let _1: T = num::cast(1);
    let _2: T = num::cast(2);

    let c0r0 = _2 / (right - left);
    let c0r1 = _0;
    let c0r2 = _0;
    let c0r3 = -(right + left) / (right - left);

    let c1r0 = _0;
    let c1r1 = _2 / (top - bottom);
    let c1r2 = _0;
    let c1r3 = -(top + bottom) / (top - bottom);

    let c2r0 = _0;
    let c2r1 = _0;
    let c2r2 = -_2 / (far - near);
    let c2r3 = -(far + near) / (far - near);

    let c3r0 = _0;
    let c3r1 = _0;
    let c3r2 = _0;
    let c3r3 = _1;

    BaseMat4::new(c0r0, c0r1, c0r2, c0r3,
                  c1r0, c1r1, c1r2, c1r3,
                  c2r0, c2r1, c2r2, c2r3,
                  c3r0, c3r1, c3r2, c3r3)
}
<|endoftext|>


<commit_before>use crate::{
    core_arch::{simd::*, simd_llvm::*, x86_64::*},
    mem::{self, transmute},
};

/// Sets packed 64-bit integers in `dst` with the supplied values.
///
/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_epi64)
#[inline]
#[target_feature(enable = "avx512f")]
pub unsafe fn _mm512_set_epi64(
    e7: i64,
    e6: i64,
    e5: i64,
    e4: i64,
    e3: i64,
    e2: i64,
    e1: i64,
    e0: i64,
) -> __m512i {
  _mm512_setr_epi64(e7, e6, e5, e4, e3, e2, e1, e0);
}

/// Sets packed 64-bit integers in `dst` with the supplied values in
/// reverse order.
///
/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_epi64)
#[inline]
#[target_feature(enable = "avx512f")]
pub unsafe fn _mm512_setr_epi64(
    e7: i64,
    e6: i64,
    e5: i64,
    e4: i64,
    e3: i64,
    e2: i64,
    e1: i64,
    e0: i64,
) -> __m512i {
    let r = i64x8(e0, e1, e2, e3, e4, e5, e6, e7);
    transmute(r)
}

#[cfg(test)]
mod tests {
    use std;
    use stdarch_test::simd_test;

    use crate::core_arch::x86::*;
    use crate::core_arch::x86_64::*;

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_cmplt_epu64_mask() {
        let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100);
        let b = _mm512_set1_epi64(-1);
        let m = _mm512_cmplt_epu64_mask(a, b);
        assert_eq!(m, 0b11001111);
    }

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_set_epi64() {
        let r = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7);
	assert_eq_m512i(r, _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0))
    }

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_setr_epi64() {
        let r = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7);
	assert_eq_m512i(r, _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0))
    }
}
<commit_msg>rustfmt<commit_after>use crate::{
    core_arch::{simd::*, simd_llvm::*, x86_64::*},
    mem::{self, transmute},
};

/// Sets packed 64-bit integers in `dst` with the supplied values.
///
/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_epi64)
#[inline]
#[target_feature(enable = "avx512f")]
pub unsafe fn _mm512_set_epi64(
    e7: i64,
    e6: i64,
    e5: i64,
    e4: i64,
    e3: i64,
    e2: i64,
    e1: i64,
    e0: i64,
) -> __m512i {
    _mm512_setr_epi64(e7, e6, e5, e4, e3, e2, e1, e0);
}

/// Sets packed 64-bit integers in `dst` with the supplied values in
/// reverse order.
///
/// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_epi64)
#[inline]
#[target_feature(enable = "avx512f")]
pub unsafe fn _mm512_setr_epi64(
    e7: i64,
    e6: i64,
    e5: i64,
    e4: i64,
    e3: i64,
    e2: i64,
    e1: i64,
    e0: i64,
) -> __m512i {
    let r = i64x8(e0, e1, e2, e3, e4, e5, e6, e7);
    transmute(r)
}

#[cfg(test)]
mod tests {
    use std;
    use stdarch_test::simd_test;

    use crate::core_arch::x86::*;
    use crate::core_arch::x86_64::*;

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_cmplt_epu64_mask() {
        let a = _mm512_set_epi64(0, 1, -1, u64::MAX as i64, i64::MAX, i64::MIN, 100, -100);
        let b = _mm512_set1_epi64(-1);
        let m = _mm512_cmplt_epu64_mask(a, b);
        assert_eq!(m, 0b11001111);
    }

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_set_epi64() {
        let r = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7);
        assert_eq_m512i(r, _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0))
    }

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_setr_epi64() {
        let r = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7);
        assert_eq_m512i(r, _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0))
    }
}
<|endoftext|>