<commit_before>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

use std::ops::{Add, AddAssign, BitAnd, BitOr, Mul, Sub, Shl, ShlAssign, Shr};
use std::io;

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized + Clone + Copy +
                  Add<Output = Self> + AddAssign +
                  BitAnd<Self, Output = Self> + BitOr<Self, Output = Self> +
                  Mul<Output = Self> + Shl<u32, Output = Self>  +
                  ShlAssign<u32> + Shr<u32, Output = Self> +
                  Shr<i8, Output = Self> + Shr<i32, Output = Self> +
                  Sub<Output = Self> {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;

  /// Convert an i16 into a `Sample`.
  fn from_i16(sample: i16) -> Self;

  /// Convert an i32 into a `Sample`.
  ///
  /// With `Sample` sometimes being smaller than a i32, there is a chance
  /// for this function to return an incorrect number. So when the number is
  /// larger of smaller than the current `Sample`, it returns `None`
  /// otherwise `Some(sample)`.
  fn from_i32(sample: i32) -> Option<Self>;

  /// Convert an i32 into a `Sample`.
  fn from_i32_lossy(sample: i32) -> Self;
}

/// A trait for defining the size of a sample.
pub trait SampleSize {
  /// The internal integer size used with `Stream::iter`.
  ///
  /// Rather than making the user of `Stream::iter` will remember what the
  /// extended size of the output sample will be, this is to map to the
  /// value based on the current integer size used.
  type Extended: Sample;
}

impl SampleSize for i8 {
  type Extended = i16;
}

impl SampleSize for i16 {
  type Extended = i32;
}

impl SampleSize for i32 {
  type Extended = i64;
}

pub trait WriteExtension: io::Write {
  fn write_u8(&mut self, number: u8) -> io::Result<()>;

  fn write_be_u16(&mut self, number: u16) -> io::Result<()>;
  fn write_le_u16(&mut self, number: u16) -> io::Result<()>;

  fn write_be_u24(&mut self, number: u32) -> io::Result<()>;
  fn write_le_u24(&mut self, number: u32) -> io::Result<()>;

  fn write_be_u32(&mut self, number: u32) -> io::Result<()>;
  fn write_le_u32(&mut self, number: u32) -> io::Result<()>;

  fn write_be_u64(&mut self, number: u64) -> io::Result<()>;
  fn write_le_u64(&mut self, number: u64) -> io::Result<()>;
}

impl<Write> WriteExtension for Write where Write: io::Write {
  fn write_u8(&mut self, number: u8) -> io::Result<()> {
    self.write_all(&[number])
  }

  fn write_be_u16(&mut self, number: u16) -> io::Result<()> {
    let mut buffer = [0; 2];

    buffer[0] = (number >> 8) as u8;
    buffer[1] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u16(&mut self, number: u16) -> io::Result<()> {
    let mut buffer = [0; 2];

    buffer[2] = number as u8;
    buffer[1] = (number >> 8) as u8;

    self.write_all(&buffer)
  }

  fn write_be_u24(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 3];

    buffer[0] = (number >> 16) as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u24(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 3];

    buffer[0] = number as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = (number >> 16) as u8;

    self.write_all(&buffer)
  }
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<commit_msg>Add implementation for writing u32<commit_after>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

use std::ops::{Add, AddAssign, BitAnd, BitOr, Mul, Sub, Shl, ShlAssign, Shr};
use std::io;

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized + Clone + Copy +
                  Add<Output = Self> + AddAssign +
                  BitAnd<Self, Output = Self> + BitOr<Self, Output = Self> +
                  Mul<Output = Self> + Shl<u32, Output = Self>  +
                  ShlAssign<u32> + Shr<u32, Output = Self> +
                  Shr<i8, Output = Self> + Shr<i32, Output = Self> +
                  Sub<Output = Self> {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;

  /// Convert an i16 into a `Sample`.
  fn from_i16(sample: i16) -> Self;

  /// Convert an i32 into a `Sample`.
  ///
  /// With `Sample` sometimes being smaller than a i32, there is a chance
  /// for this function to return an incorrect number. So when the number is
  /// larger of smaller than the current `Sample`, it returns `None`
  /// otherwise `Some(sample)`.
  fn from_i32(sample: i32) -> Option<Self>;

  /// Convert an i32 into a `Sample`.
  fn from_i32_lossy(sample: i32) -> Self;
}

/// A trait for defining the size of a sample.
pub trait SampleSize {
  /// The internal integer size used with `Stream::iter`.
  ///
  /// Rather than making the user of `Stream::iter` will remember what the
  /// extended size of the output sample will be, this is to map to the
  /// value based on the current integer size used.
  type Extended: Sample;
}

impl SampleSize for i8 {
  type Extended = i16;
}

impl SampleSize for i16 {
  type Extended = i32;
}

impl SampleSize for i32 {
  type Extended = i64;
}

pub trait WriteExtension: io::Write {
  fn write_u8(&mut self, number: u8) -> io::Result<()>;

  fn write_be_u16(&mut self, number: u16) -> io::Result<()>;
  fn write_le_u16(&mut self, number: u16) -> io::Result<()>;

  fn write_be_u24(&mut self, number: u32) -> io::Result<()>;
  fn write_le_u24(&mut self, number: u32) -> io::Result<()>;

  fn write_be_u32(&mut self, number: u32) -> io::Result<()>;
  fn write_le_u32(&mut self, number: u32) -> io::Result<()>;

  fn write_be_u64(&mut self, number: u64) -> io::Result<()>;
  fn write_le_u64(&mut self, number: u64) -> io::Result<()>;
}

impl<Write> WriteExtension for Write where Write: io::Write {
  fn write_u8(&mut self, number: u8) -> io::Result<()> {
    self.write_all(&[number])
  }

  fn write_be_u16(&mut self, number: u16) -> io::Result<()> {
    let mut buffer = [0; 2];

    buffer[0] = (number >> 8) as u8;
    buffer[1] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u16(&mut self, number: u16) -> io::Result<()> {
    let mut buffer = [0; 2];

    buffer[2] = number as u8;
    buffer[1] = (number >> 8) as u8;

    self.write_all(&buffer)
  }

  fn write_be_u24(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 3];

    buffer[0] = (number >> 16) as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u24(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 3];

    buffer[0] = number as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = (number >> 16) as u8;

    self.write_all(&buffer)
  }

  fn write_be_u32(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 4];

    buffer[0] = (number >> 24) as u8;
    buffer[1] = (number >> 16) as u8;
    buffer[2] = (number >> 8) as u8;
    buffer[3] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u32(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 4];

    buffer[0] = number as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = (number >> 16) as u8;
    buffer[3] = (number >> 24) as u8;

    self.write_all(&buffer)
  }
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<|endoftext|>


<commit_before>use std;
use x86intrin::*;

#[derive(Clone, Copy, Debug)]
pub struct FieldBit {
    m: m128i,
}

impl FieldBit {
    pub fn new(m: m128i) -> FieldBit {
        FieldBit {
            m: m,
        }
    }

    pub fn new_empty() -> FieldBit {
        FieldBit {
            m: mm_setzero_si128()
        }
    }

    pub fn from_values(v1: u16, v2: u16, v3: u16, v4: u16, v5: u16, v6: u16, v7: u16, v8: u16) -> FieldBit {
        FieldBit {
            m: mm_setr_epi16(v1 as i16, v2 as i16, v3 as i16, v4 as i16,
                             v5 as i16, v6 as i16, v7 as i16, v8 as i16)
        }
    }

    pub fn from_onebit(x: usize, y: usize) -> FieldBit {
        FieldBit {
            m: FieldBit::onebit(x, y)
        }
    }

    pub fn from_str(s: &str) -> FieldBit {
        let mut f = FieldBit::new_empty();

        assert!(s.len() % 6 == 0);

        let mut cnt = 0;
        for b in s.bytes().rev() {
            let x = 6 - (cnt % 6);
            let y = (cnt / 6) + 1;
            if b == b'1' {
                f.set(x, y);
            }
            cnt += 1;
        }

        f
    }

    pub fn as_m128i(&self) -> m128i {
        self.m
    }

    pub fn get(&self, x: usize, y: usize) -> bool {
        debug_assert!(FieldBit::check_in_range(x, y));
        mm_testz_si128(FieldBit::onebit(x, y), self.m) == 0
    }

    pub fn set(&mut self, x: usize, y: usize) {
        debug_assert!(FieldBit::check_in_range(x, y));
        self.m = mm_or_si128(FieldBit::onebit(x, y), self.m)
    }

    pub fn unset(&mut self, x: usize, y: usize) {
        debug_assert!(FieldBit::check_in_range(x, y));
        self.m = mm_andnot_si128(FieldBit::onebit(x, y), self.m)
    }

    pub fn masked_field_12(&self) -> FieldBit {
        FieldBit {
            m: mm_and_si128(self.m, mm_setr_epi16(0, 0x1FFE, 0x1FFE, 0x1FFE, 0x1FFE, 0x1FFE, 0x1FFE, 0)),
        }
    }

    pub fn masked_field_13(&self) -> FieldBit {
        FieldBit {
            m: mm_and_si128(self.m, mm_setr_epi16(0, 0x3FFE, 0x3FFE, 0x3FFE, 0x3FFE, 0x3FFE, 0x3FFE, 0)),
        }
    }

    pub fn popcount(&self) -> usize {
        let x = self.m.as_u64x2();
        let low: u64 = x.extract(0);
        let high: u64 = x.extract(1);
        (low.count_ones() + high.count_ones()) as usize
    }

    pub fn expand(&self, mask: &FieldBit) -> FieldBit {
        let mut seed = self.m;
        loop {
            let mut expanded = seed;
            expanded = mm_or_si128(mm_slli_epi16(seed, 1), expanded);
            expanded = mm_or_si128(mm_srli_epi16(seed, 1), expanded);
            expanded = mm_or_si128(mm_slli_si128(seed, 2), expanded);
            expanded = mm_or_si128(mm_srli_si128(seed, 2), expanded);
            expanded = mm_and_si128(mask.m, expanded);

            if mm_testc_si128(seed, expanded) != 0 { // seed == expanded
                return FieldBit { m: expanded };
            }
            seed = expanded;
        }
    }

    pub fn expand1(&self, mask: &FieldBit) -> FieldBit {
        let seed = self.m;
        let v1 = mm_slli_epi16(seed, 1);
        let v2 = mm_srli_epi16(seed, 1);
        let v3 = mm_slli_si128(seed, 2);
        let v4 = mm_srli_si128(seed, 2);

        let m = ((seed | v1) | (v2 | v3) | v4) & mask.m;
        FieldBit { m: m }
    }

    fn check_in_range(x: usize, y: usize) -> bool {
        x < 8 && y < 16
    }

    fn onebit(x: usize, y: usize) -> m128i {
        debug_assert!(FieldBit::check_in_range(x, y));

        let shift = ((x << 4) | y) & 0x3F;
        let hi: i64 = (x as i64) >> 2;
        let lo: i64 = hi ^ 1;

        mm_set_epi64x(hi << shift, lo << shift)
    }
}

impl std::ops::BitOr for FieldBit {
    type Output = FieldBit;

    fn bitor(self, rhs: FieldBit) -> FieldBit {
        FieldBit::new(mm_or_si128(self.m, rhs.m))
    }
}

impl std::cmp::PartialEq<FieldBit> for FieldBit {
    fn eq(&self, other: &FieldBit) -> bool {
        let x = mm_xor_si128(self.m, other.m);
        mm_testz_si128(x, x) == 1
    }
}

impl std::fmt::Display for FieldBit {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let x = self.m.as_u16x8();
        write!(f, "({}, {}, {}, {}, {}, {}, {}, {})",
               x.extract(0), x.extract(1), x.extract(2), x.extract(3),
               x.extract(4), x.extract(5), x.extract(6), x.extract(7))
    }
}

#[cfg(test)]
mod tests {
    use field;
    use field_bit::FieldBit;

    #[test]
    fn test_empty() {
        let fb = FieldBit::new_empty();
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                assert_eq!(fb.get(x, y), false);
            }
        }
    }

    #[test]
    fn test_from_value() {
        let fb = FieldBit::from_values(1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7);
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                assert_eq!(fb.get(x, y), x == y, "failed at x={}, y={}, fb.get(x, y)={}", x, y, fb.get(x, y));
            }
        }
    }

    #[test]
    fn test_from_str() {
        let fb = FieldBit::from_str(concat!(
            "111...",
            "......",
            "111..."));

        for x in 0 .. 8 {
            for y in 0 .. 16 {
                let b = (y == 1 || y == 3) && (1 <= x && x <= 3);
                assert_eq!(fb.get(x, y), b, "x={}, y={}", x, y);
            }
        }
    }

    #[test]
    fn test_set_get() {
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                let mut fb = FieldBit::new_empty();
                assert!(!fb.get(x, y));
                fb.set(x, y);
                assert!(fb.get(x, y));
                fb.unset(x, y);
                assert!(!fb.get(x, y));
            }
        }
    }

    #[test]
    fn test_masked_field() {
        let fb = FieldBit::from_values(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
        let fb12 = fb.masked_field_12();
        let fb13 = fb.masked_field_13();

        for x in 0 .. field::MAP_WIDTH {
            for y in 0 .. field::MAP_HEIGHT {
                assert!(fb.get(x, y), "x={}, y={}", x, y);
                assert_eq!(fb12.get(x, y), 1 <= x && x <= 6 && 1 <= y && y <= 12, "x={}, y={}", x, y);
                assert_eq!(fb13.get(x, y), 1 <= x && x <= 6 && 1 <= y && y <= 13, "x={}, y={}", x, y);
            }
        }
    }

    #[test]
    fn test_popcount() {
        let fb = FieldBit::from_values(1, 2, 3, 4, 5, 6, 7, 8);
        assert_eq!(fb.popcount(), 1 + 1 + 2 + 1 + 2 + 2 + 3 + 1)
    }

    #[test]
    fn test_expand() {
        let mask = FieldBit::from_str(concat!(
            ".1....",
            "1.11..",
            "1.1...",
            "1.1...",
        ));

        let expected = FieldBit::from_str(concat!(
            "..11..",
            "..1...",
            "..1..."));

        let actual = FieldBit::from_onebit(3, 1).expand(&mask);
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                assert_eq!(actual.get(x, y), expected.get(x, y), "x={}, y={}", x, y);
            }
        }
    }

    #[test]
    fn test_expand1() {
        let mask = FieldBit::from_str(concat!(
            "111111",
            "111111",
            "111111"));

        let seed = FieldBit::from_str(concat!(
            "......",
            "1...1.",
            "......"));

        let expected = FieldBit::from_str(concat!(
            "1...1.",
            "11.111",
            "1...1."));

        let actual = seed.expand1(&mask);
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                assert_eq!(actual.get(x, y), expected.get(x, y), "x={}, y={}", x, y);
            }
        }
    }

    #[test]
    fn test_eq() {
        let fb1 = FieldBit::from_str(concat!(
            "1....1",
            "1....1",
            "111111"));
        let fb2 = FieldBit::from_str(concat!(
            "111111",
            "1....1",
            "1....1"));

        assert!(fb1 == fb1);
        assert!(fb2 == fb2);
        assert!(fb1 != fb2);
    }

    #[test]
    fn test_bitor() {
        let fb1 = FieldBit::from_str(concat!(
            "1....1",
            "1....1",
            "111111"));
        let fb2 = FieldBit::from_str(concat!(
            "111111",
            "1....1",
            "1....1"));
        let expected = FieldBit::from_str(concat!(
            "111111",
            "1....1",
            "111111"));

        assert_eq!(expected, fb1 | fb2);
    }
}
<commit_msg>Add FieldBit256<commit_after>use std;
use x86intrin::*;

#[derive(Clone, Copy, Debug)]
pub struct FieldBit {
    m: m128i,
}

#[derive(Clone, Copy, Debug)]
pub struct FieldBit256 {
    m: m256i,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LowHigh {
    LOW,
    HIGH,
}

impl FieldBit {
    pub fn new(m: m128i) -> FieldBit {
        FieldBit {
            m: m,
        }
    }

    pub fn new_empty() -> FieldBit {
        FieldBit {
            m: mm_setzero_si128()
        }
    }

    pub fn from_values(v1: u16, v2: u16, v3: u16, v4: u16, v5: u16, v6: u16, v7: u16, v8: u16) -> FieldBit {
        FieldBit {
            m: mm_setr_epi16(v1 as i16, v2 as i16, v3 as i16, v4 as i16,
                             v5 as i16, v6 as i16, v7 as i16, v8 as i16)
        }
    }

    pub fn from_onebit(x: usize, y: usize) -> FieldBit {
        FieldBit {
            m: FieldBit::onebit(x, y)
        }
    }

    pub fn from_str(s: &str) -> FieldBit {
        let mut f = FieldBit::new_empty();

        assert!(s.len() % 6 == 0);

        let mut cnt = 0;
        for b in s.bytes().rev() {
            let x = 6 - (cnt % 6);
            let y = (cnt / 6) + 1;
            if b == b'1' {
                f.set(x, y);
            }
            cnt += 1;
        }

        f
    }

    pub fn as_m128i(&self) -> m128i {
        self.m
    }

    pub fn get(&self, x: usize, y: usize) -> bool {
        debug_assert!(FieldBit::check_in_range(x, y));
        mm_testz_si128(FieldBit::onebit(x, y), self.m) == 0
    }

    pub fn set(&mut self, x: usize, y: usize) {
        debug_assert!(FieldBit::check_in_range(x, y));
        self.m = mm_or_si128(FieldBit::onebit(x, y), self.m)
    }

    pub fn unset(&mut self, x: usize, y: usize) {
        debug_assert!(FieldBit::check_in_range(x, y));
        self.m = mm_andnot_si128(FieldBit::onebit(x, y), self.m)
    }

    pub fn masked_field_12(&self) -> FieldBit {
        FieldBit {
            m: mm_and_si128(self.m, mm_setr_epi16(0, 0x1FFE, 0x1FFE, 0x1FFE, 0x1FFE, 0x1FFE, 0x1FFE, 0)),
        }
    }

    pub fn masked_field_13(&self) -> FieldBit {
        FieldBit {
            m: mm_and_si128(self.m, mm_setr_epi16(0, 0x3FFE, 0x3FFE, 0x3FFE, 0x3FFE, 0x3FFE, 0x3FFE, 0)),
        }
    }

    pub fn popcount(&self) -> usize {
        let x = self.m.as_u64x2();
        let low: u64 = x.extract(0);
        let high: u64 = x.extract(1);
        (low.count_ones() + high.count_ones()) as usize
    }

    pub fn expand(&self, mask: &FieldBit) -> FieldBit {
        let mut seed = self.m;
        loop {
            let mut expanded = seed;
            expanded = mm_or_si128(mm_slli_epi16(seed, 1), expanded);
            expanded = mm_or_si128(mm_srli_epi16(seed, 1), expanded);
            expanded = mm_or_si128(mm_slli_si128(seed, 2), expanded);
            expanded = mm_or_si128(mm_srli_si128(seed, 2), expanded);
            expanded = mm_and_si128(mask.m, expanded);

            if mm_testc_si128(seed, expanded) != 0 { // seed == expanded
                return FieldBit { m: expanded };
            }
            seed = expanded;
        }
    }

    pub fn expand1(&self, mask: &FieldBit) -> FieldBit {
        let seed = self.m;
        let v1 = mm_slli_epi16(seed, 1);
        let v2 = mm_srli_epi16(seed, 1);
        let v3 = mm_slli_si128(seed, 2);
        let v4 = mm_srli_si128(seed, 2);

        let m = ((seed | v1) | (v2 | v3) | v4) & mask.m;
        FieldBit { m: m }
    }

    fn check_in_range(x: usize, y: usize) -> bool {
        x < 8 && y < 16
    }

    fn onebit(x: usize, y: usize) -> m128i {
        debug_assert!(FieldBit::check_in_range(x, y));

        let shift = ((x << 4) | y) & 0x3F;
        let hi: i64 = (x as i64) >> 2;
        let lo: i64 = hi ^ 1;

        mm_set_epi64x(hi << shift, lo << shift)
    }
}

impl std::ops::BitOr for FieldBit {
    type Output = FieldBit;

    fn bitor(self, rhs: FieldBit) -> FieldBit {
        FieldBit::new(mm_or_si128(self.m, rhs.m))
    }
}

impl std::cmp::PartialEq<FieldBit> for FieldBit {
    fn eq(&self, other: &FieldBit) -> bool {
        let x = mm_xor_si128(self.m, other.m);
        mm_testz_si128(x, x) == 1
    }
}

impl std::fmt::Display for FieldBit {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let x = self.m.as_u16x8();
        write!(f, "({}, {}, {}, {}, {}, {}, {}, {})",
               x.extract(0), x.extract(1), x.extract(2), x.extract(3),
               x.extract(4), x.extract(5), x.extract(6), x.extract(7))
    }
}

impl FieldBit256 {
    pub fn new(m: m256i) -> FieldBit256 {
        FieldBit256 {
            m: m,
        }
    }

    pub fn new_empty() -> FieldBit256 {
        FieldBit256 {
            m: mm256_setzero_si256()
        }
    }

    pub fn from_low_high(low: FieldBit, high: FieldBit) -> FieldBit256 {
        let m = mm256_inserti128_si256(mm256_castsi128_si256(low.m), high.m, 1);
        FieldBit256 {
            m: m
        }
    }

    pub fn get(&self, lowhigh: LowHigh, x: usize, y: usize) -> bool {
        debug_assert!(FieldBit256::check_in_range(x, y));
        mm256_testz_si256(FieldBit256::onebit(lowhigh, x, y), self.m) == 0
    }

    fn check_in_range(x: usize, y: usize) -> bool {
        x < 8 && y < 16
    }

    fn onebit(lowhigh: LowHigh, x: usize, y: usize) -> m256i {
        debug_assert!(FieldBit256::check_in_range(x, y));

        // TODO(mayah): Maybe we have more good solution.

        let shift = ((x << 4) | y) & 0x3F;
        let zero = mm256_setzero_si256();
        if lowhigh == LowHigh::LOW {
            if x < 4 {
                return mm256_insert_epi64(zero, 1 << shift, 0)
            } else {
                return mm256_insert_epi64(zero, 1 << shift, 1)
            }
        } else {
            if x < 4 {
                return mm256_insert_epi64(zero, 1 << shift, 2)
            } else {
                return mm256_insert_epi64(zero, 1 << shift, 3)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use field;
    use field_bit::FieldBit;

    #[test]
    fn test_empty() {
        let fb = FieldBit::new_empty();
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                assert_eq!(fb.get(x, y), false);
            }
        }
    }

    #[test]
    fn test_from_value() {
        let fb = FieldBit::from_values(1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7);
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                assert_eq!(fb.get(x, y), x == y, "failed at x={}, y={}, fb.get(x, y)={}", x, y, fb.get(x, y));
            }
        }
    }

    #[test]
    fn test_from_str() {
        let fb = FieldBit::from_str(concat!(
            "111...",
            "......",
            "111..."));

        for x in 0 .. 8 {
            for y in 0 .. 16 {
                let b = (y == 1 || y == 3) && (1 <= x && x <= 3);
                assert_eq!(fb.get(x, y), b, "x={}, y={}", x, y);
            }
        }
    }

    #[test]
    fn test_set_get() {
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                let mut fb = FieldBit::new_empty();
                assert!(!fb.get(x, y));
                fb.set(x, y);
                assert!(fb.get(x, y));
                fb.unset(x, y);
                assert!(!fb.get(x, y));
            }
        }
    }

    #[test]
    fn test_masked_field() {
        let fb = FieldBit::from_values(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
        let fb12 = fb.masked_field_12();
        let fb13 = fb.masked_field_13();

        for x in 0 .. field::MAP_WIDTH {
            for y in 0 .. field::MAP_HEIGHT {
                assert!(fb.get(x, y), "x={}, y={}", x, y);
                assert_eq!(fb12.get(x, y), 1 <= x && x <= 6 && 1 <= y && y <= 12, "x={}, y={}", x, y);
                assert_eq!(fb13.get(x, y), 1 <= x && x <= 6 && 1 <= y && y <= 13, "x={}, y={}", x, y);
            }
        }
    }

    #[test]
    fn test_popcount() {
        let fb = FieldBit::from_values(1, 2, 3, 4, 5, 6, 7, 8);
        assert_eq!(fb.popcount(), 1 + 1 + 2 + 1 + 2 + 2 + 3 + 1)
    }

    #[test]
    fn test_expand() {
        let mask = FieldBit::from_str(concat!(
            ".1....",
            "1.11..",
            "1.1...",
            "1.1...",
        ));

        let expected = FieldBit::from_str(concat!(
            "..11..",
            "..1...",
            "..1..."));

        let actual = FieldBit::from_onebit(3, 1).expand(&mask);
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                assert_eq!(actual.get(x, y), expected.get(x, y), "x={}, y={}", x, y);
            }
        }
    }

    #[test]
    fn test_expand1() {
        let mask = FieldBit::from_str(concat!(
            "111111",
            "111111",
            "111111"));

        let seed = FieldBit::from_str(concat!(
            "......",
            "1...1.",
            "......"));

        let expected = FieldBit::from_str(concat!(
            "1...1.",
            "11.111",
            "1...1."));

        let actual = seed.expand1(&mask);
        for x in 0 .. 8 {
            for y in 0 .. 16 {
                assert_eq!(actual.get(x, y), expected.get(x, y), "x={}, y={}", x, y);
            }
        }
    }

    #[test]
    fn test_eq() {
        let fb1 = FieldBit::from_str(concat!(
            "1....1",
            "1....1",
            "111111"));
        let fb2 = FieldBit::from_str(concat!(
            "111111",
            "1....1",
            "1....1"));

        assert!(fb1 == fb1);
        assert!(fb2 == fb2);
        assert!(fb1 != fb2);
    }

    #[test]
    fn test_bitor() {
        let fb1 = FieldBit::from_str(concat!(
            "1....1",
            "1....1",
            "111111"));
        let fb2 = FieldBit::from_str(concat!(
            "111111",
            "1....1",
            "1....1"));
        let expected = FieldBit::from_str(concat!(
            "111111",
            "1....1",
            "111111"));

        assert_eq!(expected, fb1 | fb2);
    }
}

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

    #[test]
    fn test_constructor() {
        let fb256 = FieldBit256::new_empty();

        for x in 0 .. 8 {
            for y in 0 .. 16 {
                assert!(!fb256.get(LowHigh::LOW, x, y));
                assert!(!fb256.get(LowHigh::HIGH, x, y));
            }
        }
    }

    #[test]
    fn test_from_low_high() {
        let mut low = FieldBit::new_empty();
        let mut high = FieldBit::new_empty();
        low.set(1, 3);
        low.set(4, 8);
        high.set(2, 4);
        high.set(5, 9);

        let fb256 = FieldBit256::from_low_high(low, high);
        assert!(fb256.get(LowHigh::LOW, 1, 3));
        assert!(fb256.get(LowHigh::LOW, 4, 8));
        assert!(fb256.get(LowHigh::HIGH, 2, 4));
        assert!(fb256.get(LowHigh::HIGH, 5, 9));

        assert!(!fb256.get(LowHigh::HIGH, 1, 3));
        assert!(!fb256.get(LowHigh::HIGH, 4, 8));
        assert!(!fb256.get(LowHigh::LOW, 2, 4));
        assert!(!fb256.get(LowHigh::LOW, 5, 9));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Module that provides interaction with radare2.
//! Uses r2pipe.

use r2pipe::R2Pipe;

use rustc_serialize::json::{Json, ToJson, DecodeResult};
use rustc_serialize::json;
use std::collections::BTreeMap;

// All the struct required for json parsing,
use super::structs::*;

pub struct R2 {
	pipe:   R2Pipe,
	readin: String,
}

pub trait Search {
	fn get_values(&self, key: &[&str], deep: bool) -> Option<Json>;
}

impl Search for Json {
	fn get_values(&self, key: &[&str], deep: bool) -> Option<Json> {
		match *self {
			Json::Array(ref arr) => {
				let mut tmp = Vec::new();
				for x in arr.iter() {
					x.get_values(key, deep)
						.map_or((), |e| tmp.push(e));
				}
				if tmp.len() > 0 {
					return Some(tmp.to_json());
				}
			},

			Json::Object(ref obj) => {
				let mut result: BTreeMap<String, Json> = BTreeMap::new();
				for k in key {
					obj.get((*k)).map_or((), |val| {
						result.insert((*k).to_string(), val.clone());
					});
				}

				// If we have found something, return.
				if result.keys().len() > 0 {
					return Some(result.to_json());
				}

				// If we don't want a deep search, we just return None at this point.
				if !deep {
					return None;
				}

				// Manually iterate through the keys and check if the values have the key.
				for (_, val) in obj.iter() {
					let res = val.get_values(key, deep);
					if res.is_some() {
						return res;
					}
				}
			},

			_ => return None,
		}
		return None;
	}
}

// fn send and recv allow users to send their own commands,
// i.e. The ones that are not currently abstracted by the R2 API.
// Ideally, all commonly used commands must be supported for easier use.
impl R2 {
	// TODO: Use an error type
	pub fn new(path: Option<String>) -> Result<R2, String> {
		if path.is_none() && !R2::in_session() {
			let e = "No r2 session open. Please specify path!".to_owned();
			return Err(e);
		}

		// This means that path is `Some` or we have an open session.
		let pipe = open_pipe!(path).unwrap();
		Ok(R2 { pipe: pipe, readin: String::new() })
	}

	pub fn in_session() -> bool {
		match R2Pipe::in_session() {
			Some(_) => true,
			None    => false,
		}
	}

	pub fn from(r2p: R2Pipe) -> R2 {
		R2 { pipe: r2p, readin: String::new() }
	}

	// Does some basic configurations (sane defaults).
	pub fn init(&mut self) {
		self.send("e asm.esil = true");
		self.send("e scr.color = false");
		self.send("aaa");
		self.flush();
	}

	pub fn close(&mut self) {
		self.send("q!");
	}

	pub fn send(&mut self, cmd: &str) {
		self.readin = self.pipe.cmd(cmd);
	}

	pub fn recv(&mut self) -> String {
		let res = self.readin.clone();
		self.flush();
		res
	}

	pub fn recv_json(&mut self) -> Json {
		let res = self.recv().replace("\n", "");
		Json::from_str(&*res).unwrap()
	}

	pub fn flush(&mut self) {
		self.readin = String::from("");
	}

	pub fn analyze(&mut self) {
		self.send("aa");
		self.flush();
	}

	pub fn get_function(&mut self, func: &str) -> DecodeResult<LFunctionInfo> {
		let cmd = format!("pdfj @ {}", func);
		self.send(&*cmd);
		let raw_json = self.recv();
		// Handle Error here.
		json::decode(&*raw_json)
	}

	// get 'n' (or 16) instructions at 'offset' (or current position if offset in `None`)
	pub fn get_insts(&mut self, n: Option<u64>, offset: Option<&str>) -> DecodeResult<Vec<LOpInfo>> {
		let n = n.unwrap_or(16);
		let offset: &str = offset.unwrap_or_default();
		let mut cmd = format!("pdj{}", n);
		if offset.len() > 0 {
			cmd = format!("{} @ {}", cmd, offset);
		}
		self.send(&*cmd);
		let raw_json = self.recv();
		json::decode(&*raw_json)
	}

	pub fn get_reg_info(&mut self) -> DecodeResult<LRegInfo> {
		self.send("drpj");
		let raw_json = self.recv();
		json::decode(&*raw_json)
	}

	pub fn get_flag_info(&mut self) -> DecodeResult<Vec<LFlagInfo>> {
		self.send("fj");
		let raw_json = self.recv();
		json::decode(&*raw_json)
	}

	pub fn get_bin_info(&mut self) -> DecodeResult<LBinInfo> {
		self.send("ij");
		let raw_json = self.recv();
		json::decode(&*raw_json)
	}

	pub fn get_fn_list(&mut self) -> Json {
		self.send("aflj");
		self.recv_json()
	}
}
<commit_msg>Fix for latest r2pipe<commit_after>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Module that provides interaction with radare2.
//! Uses r2pipe.

use r2pipe::R2Pipe;

use rustc_serialize::json::{Json, ToJson, DecodeResult};
use rustc_serialize::json;
use std::collections::BTreeMap;

// All the struct required for json parsing,
use super::structs::*;

pub struct R2 {
	pipe:   R2Pipe,
	readin: String,
}

pub trait Search {
	fn get_values(&self, key: &[&str], deep: bool) -> Option<Json>;
}

impl Search for Json {
	fn get_values(&self, key: &[&str], deep: bool) -> Option<Json> {
		match *self {
			Json::Array(ref arr) => {
				let mut tmp = Vec::new();
				for x in arr.iter() {
					x.get_values(key, deep)
						.map_or((), |e| tmp.push(e));
				}
				if tmp.len() > 0 {
					return Some(tmp.to_json());
				}
			},

			Json::Object(ref obj) => {
				let mut result: BTreeMap<String, Json> = BTreeMap::new();
				for k in key {
					obj.get((*k)).map_or((), |val| {
						result.insert((*k).to_string(), val.clone());
					});
				}

				// If we have found something, return.
				if result.keys().len() > 0 {
					return Some(result.to_json());
				}

				// If we don't want a deep search, we just return None at this point.
				if !deep {
					return None;
				}

				// Manually iterate through the keys and check if the values have the key.
				for (_, val) in obj.iter() {
					let res = val.get_values(key, deep);
					if res.is_some() {
						return res;
					}
				}
			},

			_ => return None,
		}
		return None;
	}
}

// fn send and recv allow users to send their own commands,
// i.e. The ones that are not currently abstracted by the R2 API.
// Ideally, all commonly used commands must be supported for easier use.
impl R2 {
	// TODO: Use an error type
	pub fn new(path: Option<String>) -> Result<R2, String> {
		if path.is_none() && !R2::in_session() {
			let e = "No r2 session open. Please specify path!".to_owned();
			return Err(e);
		}

		// This means that path is `Some` or we have an open session.
		let pipe = open_pipe!(path).unwrap();
		Ok(R2 { pipe: pipe, readin: String::new() })
	}

	pub fn in_session() -> bool {
		match R2Pipe::in_session() {
			Some(_) => true,
			None    => false,
		}
	}

	pub fn from(r2p: R2Pipe) -> R2 {
		R2 { pipe: r2p, readin: String::new() }
	}

	// Does some basic configurations (sane defaults).
	pub fn init(&mut self) {
		self.send("e asm.esil = true");
		self.send("e scr.color = false");
		self.send("aaa");
		self.flush();
	}

	pub fn close(&mut self) {
		self.send("q!");
	}

	pub fn send(&mut self, cmd: &str) {
		self.readin = self.pipe.cmd(cmd).unwrap();
	}

	pub fn recv(&mut self) -> String {
		let res = self.readin.clone();
		self.flush();
		res
	}

	pub fn recv_json(&mut self) -> Json {
		let res = self.recv().replace("\n", "");
		Json::from_str(&*res).unwrap()
	}

	pub fn flush(&mut self) {
		self.readin = String::from("");
	}

	pub fn analyze(&mut self) {
		self.send("aa");
		self.flush();
	}

	pub fn get_function(&mut self, func: &str) -> DecodeResult<LFunctionInfo> {
		let cmd = format!("pdfj @ {}", func);
		self.send(&*cmd);
		let raw_json = self.recv();
		// Handle Error here.
		json::decode(&*raw_json)
	}

	// get 'n' (or 16) instructions at 'offset' (or current position if offset in `None`)
	pub fn get_insts(&mut self, n: Option<u64>, offset: Option<&str>) -> DecodeResult<Vec<LOpInfo>> {
		let n = n.unwrap_or(16);
		let offset: &str = offset.unwrap_or_default();
		let mut cmd = format!("pdj{}", n);
		if offset.len() > 0 {
			cmd = format!("{} @ {}", cmd, offset);
		}
		self.send(&*cmd);
		let raw_json = self.recv();
		json::decode(&*raw_json)
	}

	pub fn get_reg_info(&mut self) -> DecodeResult<LRegInfo> {
		self.send("drpj");
		let raw_json = self.recv();
		json::decode(&*raw_json)
	}

	pub fn get_flag_info(&mut self) -> DecodeResult<Vec<LFlagInfo>> {
		self.send("fj");
		let raw_json = self.recv();
		json::decode(&*raw_json)
	}

	pub fn get_bin_info(&mut self) -> DecodeResult<LBinInfo> {
		self.send("ij");
		let raw_json = self.recv();
		json::decode(&*raw_json)
	}

	pub fn get_fn_list(&mut self) -> Json {
		self.send("aflj");
		self.recv_json()
	}
}
<|endoftext|>


<commit_before>use character::controls::CharacterControl;
use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_app::controls::{Control, TilemapControls};
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::{GlContext, KeyboardInput, MouseButton};
use glutin::ElementState::{Pressed, Released};
use glutin::VirtualKeyCode::{A, D, Escape, R, S, W, X, Z};
use glutin::dpi::LogicalSize;

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct WindowContext {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl WindowContext {
  pub fn new() -> WindowContext {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      let logical_size = LogicalSize::new(RESOLUTION_X.into(), RESOLUTION_Y.into());
      window_title
        .with_dimensions(logical_size)
        .with_min_dimensions(logical_size)
        .with_max_dimensions(logical_size)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("No monitor found")
      };
      let monitor_resolution = monitor.get_dimensions();

      let resolution = ((monitor_resolution.width as f32 * 16.0 / 9.0) as u32, monitor_resolution.height);

      let logical_size = LogicalSize::new(resolution.0.into(), resolution.1.into());
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(logical_size)
                  .with_min_dimensions(logical_size)
                  .with_max_dimensions(logical_size)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8);

    let (window, device, factory, rtv, dsv) =
      gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    WindowContext {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WindowStatus {
  Open,
  Close,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> WindowStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for WindowContext {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    if cfg!(feature = "windowed") {
      (RESOLUTION_X as f32, RESOLUTION_Y as f32)
    } else {
      let monitor = self.events_loop.get_available_monitors().nth(0).expect("No monitor found");
      let monitor_resolution = monitor.get_dimensions();
      ((monitor_resolution.width as f32 * 16.0 / 9.0) as f32, monitor_resolution.height as f32)
    }
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.get_hidpi_factor() as f32
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> WindowStatus {
    use glutin::WindowEvent::{CursorMoved, CloseRequested, MouseInput};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };

    let m_pos = &mut self.mouse_pos;

    let mut game_status = WindowStatus::Open;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => { process_keyboard_input(input, controls) },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            WindowStatus::Open
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            WindowStatus::Open
          }
          CursorMoved { position, .. } => {
            *m_pos = ((position.x as f32).into(), (position.y as f32).into());
            WindowStatus::Open
          }
          CloseRequested => WindowStatus::Close,
          _ => WindowStatus::Open,
        }
      } else {
        WindowStatus::Open
      };
    });
    game_status
  }
}

fn process_keyboard_input(input: glutin::KeyboardInput, controls: &mut TilemapControls) -> WindowStatus {
  match input {
    KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
      controls.zoom(&Control::Negative);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Plus);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Released);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
      controls.move_character(CharacterControl::Up);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::Down);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::YMoveStop);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
      controls.move_character(CharacterControl::Left);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::Right);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::XMoveStop);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(true);
    },
    KeyboardInput { state: Released, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(false);
    },
    KeyboardInput { state: Pressed, modifiers, .. } => {
      if modifiers.ctrl {
        controls.ctrl_pressed(true);
      }
    }
    KeyboardInput { state: Released, modifiers, .. } => {
      if !modifiers.ctrl {
        controls.ctrl_pressed(false);
      }
    }
  }
  if let Some(Escape) = input.virtual_keycode {
    WindowStatus::Close
  } else {
    WindowStatus::Open
  }
}

<commit_msg>Fix MacOS windowed-blank-screen issue<commit_after>use character::controls::CharacterControl;
use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_app::controls::{Control, TilemapControls};
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::{GlContext, KeyboardInput, MouseButton};
use glutin::ElementState::{Pressed, Released};
use glutin::VirtualKeyCode::{A, D, Escape, R, S, W, X, Z};
use glutin::dpi::{LogicalSize, PhysicalSize};

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct WindowContext {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl WindowContext {
  pub fn new() -> WindowContext {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      let logical_size = LogicalSize::new(RESOLUTION_X.into(), RESOLUTION_Y.into());
      window_title
        .with_dimensions(logical_size)
        .with_min_dimensions(logical_size)
        .with_max_dimensions(logical_size)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("No monitor found")
      };
      let monitor_resolution = monitor.get_dimensions();

      let resolution = ((monitor_resolution.width as f32 * 16.0 / 9.0) as u32, monitor_resolution.height);

      let logical_size = LogicalSize::new(resolution.0.into(), resolution.1.into());
      window_title.with_fullscreen(Some(monitor))
                  .with_decorations(false)
                  .with_dimensions(logical_size)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8);

    let (window, device, factory, rtv, dsv) =
      gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    WindowContext {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WindowStatus {
  Open,
  Close,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> WindowStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for WindowContext {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    if cfg!(feature = "windowed") {
      (RESOLUTION_X as f32, RESOLUTION_Y as f32)
    } else {
      let monitor = self.events_loop.get_available_monitors().nth(0).expect("No monitor found");
      let monitor_resolution = monitor.get_dimensions();
      ((monitor_resolution.width as f32 * 16.0 / 9.0) as f32, monitor_resolution.height as f32)
    }
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.get_hidpi_factor() as f32
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> WindowStatus {
    use glutin::WindowEvent::{CursorMoved, CloseRequested, MouseInput};

    // Hack for MacOS 10.14
    let resolution = self.get_viewport_size();
    self.window.resize(PhysicalSize::new(resolution.0.into(), resolution.1.into()));

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };

    let m_pos = &mut self.mouse_pos;
    let mut game_status = WindowStatus::Open;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => { process_keyboard_input(input, controls) },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            WindowStatus::Open
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            WindowStatus::Open
          }
          CursorMoved { position, .. } => {
            *m_pos = ((position.x as f32).into(), (position.y as f32).into());
            WindowStatus::Open
          }
          CloseRequested => WindowStatus::Close,
          _ => WindowStatus::Open,
        }
      } else {
        WindowStatus::Open
      };
    });
    game_status
  }
}

fn process_keyboard_input(input: glutin::KeyboardInput, controls: &mut TilemapControls) -> WindowStatus {
  match input {
    KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
      controls.zoom(&Control::Negative);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Plus);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Released);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
      controls.move_character(CharacterControl::Up);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::Down);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::YMoveStop);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
      controls.move_character(CharacterControl::Left);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::Right);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::XMoveStop);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(true);
    },
    KeyboardInput { state: Released, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(false);
    },
    KeyboardInput { state: Pressed, modifiers, .. } => {
      if modifiers.ctrl {
        controls.ctrl_pressed(true);
      }
    }
    KeyboardInput { state: Released, modifiers, .. } => {
      if !modifiers.ctrl {
        controls.ctrl_pressed(false);
      }
    }
  }
  if let Some(Escape) = input.virtual_keycode {
    WindowStatus::Close
  } else {
    WindowStatus::Open
  }
}

<|endoftext|>


<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use gl;
use gl::types::{
    GLfloat,
    GLint,
    GLsizei,
    GLsizeiptr,
    GLuint,
};
use std::ptr;
use std::mem;
use shader_utils::{compile_shader};
use BackEnd;

// Local crate.
use Texture;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;

varying vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;
attribute vec2 a_v2TexCoord;

uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        v_v2TexCoord = a_v2TexCoord;
        v_v4FillColor = a_v4FillColor;
        gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = texture2D(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

struct TriListXYRGBA {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
}

impl Drop for TriListXYRGBA {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            TriListXYRGBA {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
            }
        }
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
    a_v2TexCoord: GLuint,
}

impl Drop for TriListXYRGBAUV {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            let a_v2TexCoord = "a_v2TexCoord".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            TriListXYRGBAUV {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
                a_v2TexCoord: a_v2TexCoord as GLuint,
            }
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // id of buffer for xy positions.
    position_id: GLuint,
    // id of buffer for rgba colors.
    fill_color_id: GLuint,
    // id of buffer for uv texture coords.
    tex_coord_id: GLuint,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        unsafe {
            let mut vbo : [GLuint, ..3] = [0, ..3];
            gl::GenBuffers(3, vbo.as_mut_ptr());
            let position_id = vbo[0];
            let fill_color_id = vbo[1];
            let tex_coord_id = vbo[2];

            Gl {
                tri_list_xy_rgba: TriListXYRGBA::new(),
                tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
                position_id: position_id,
                fill_color_id: fill_color_id,
                tex_coord_id: tex_coord_id,
                current_program: None,
            }
        }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba;
        // xy makes two floats.
        let size_vertices: i32 = 2;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_vertices = gl::FALSE;
        // The data is tightly packed.
        let stride_vertices = 0;
        gl::BindBuffer(
            gl::ARRAY_BUFFER,   // buffer type
            self.position_id    // position buffer for xy coordinates
        );
        unsafe {
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_colors = 4;
        let normalize_colors = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_colors,
                gl::FLOAT,
                normalize_colors,
                stride_fill_colors,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba_uv;
        let size_vertices: i32 = 2;
        let normalize_vertices = gl::FALSE;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_vertices = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER, self.position_id);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_color = 4;
        let normalize_fill_color = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_color,
                gl::FLOAT,
                normalize_fill_color,
                stride_fill_colors,
                ptr::null()
            );
        }

        // uv makes two floats.
        let size_tex_coord = 2;
        let texture_coords_byte_len = (
                texture_coords.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_texture_coords = gl::FALSE;
        // The data is tightly packed.
        let stride_texture_coords = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.tex_coord_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                texture_coords_byte_len,
                mem::transmute(&texture_coords[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v2TexCoord as GLuint,
                size_tex_coord,
                gl::FLOAT,
                normalize_texture_coords,
                stride_texture_coords,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
    }
}

<commit_msg>Fix issue #304<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use gl;
use gl::types::{
    GLfloat,
    GLint,
    GLsizei,
    GLsizeiptr,
    GLuint,
};
use std::ptr;
use std::mem;
use shader_utils::{compile_shader};
use BackEnd;

// Local crate.
use Texture;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;

varying vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;
attribute vec2 a_v2TexCoord;

uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        v_v2TexCoord = a_v2TexCoord;
        v_v4FillColor = a_v4FillColor;
        gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = texture2D(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

struct TriListXYRGBA {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
}

impl Drop for TriListXYRGBA {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            TriListXYRGBA {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
            }
        }
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
    a_v2TexCoord: GLuint,
}

impl Drop for TriListXYRGBAUV {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            let a_v2TexCoord = "a_v2TexCoord".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            TriListXYRGBAUV {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
                a_v2TexCoord: a_v2TexCoord as GLuint,
            }
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // id of buffer for xy positions.
    position_id: GLuint,
    // id of buffer for rgba colors.
    fill_color_id: GLuint,
    // id of buffer for uv texture coords.
    tex_coord_id: GLuint,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        unsafe {
            let mut vbo : [GLuint, ..3] = [0, ..3];
            gl::GenBuffers(3, vbo.as_mut_ptr());
            let position_id = vbo[0];
            let fill_color_id = vbo[1];
            let tex_coord_id = vbo[2];

            Gl {
                tri_list_xy_rgba: TriListXYRGBA::new(),
                tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
                position_id: position_id,
                fill_color_id: fill_color_id,
                tex_coord_id: tex_coord_id,
                current_program: None,
            }
        }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba;
        // xy makes two floats.
        let size_vertices: i32 = 2;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_vertices = gl::FALSE;
        // The data is tightly packed.
        let stride_vertices = 0;
        gl::BindBuffer(
            gl::ARRAY_BUFFER,   // buffer type
            self.position_id    // position buffer for xy coordinates
        );
        unsafe {
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_colors = 4;
        let normalize_colors = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_colors,
                gl::FLOAT,
                normalize_colors,
                stride_fill_colors,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba_uv;
        let size_vertices: i32 = 2;
        let normalize_vertices = gl::FALSE;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_vertices = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER, self.position_id);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_color = 4;
        let normalize_fill_color = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_color,
                gl::FLOAT,
                normalize_fill_color,
                stride_fill_colors,
                ptr::null()
            );
        }

        // uv makes two floats.
        let size_tex_coord = 2;
        let texture_coords_byte_len = (
                texture_coords.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_texture_coords = gl::FALSE;
        // The data is tightly packed.
        let stride_texture_coords = 0;
        gl::EnableVertexAttribArray(shader.a_v2TexCoord as GLuint);
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.tex_coord_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                texture_coords_byte_len,
                mem::transmute(&texture_coords[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v2TexCoord as GLuint,
                size_tex_coord,
                gl::FLOAT,
                normalize_texture_coords,
                stride_texture_coords,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
        gl::DisableVertexAttribArray(shader.a_v2TexCoord as GLuint);
    }
}

<|endoftext|>