<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::{self, Metadata, metadata_parser};

/// 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>;
}

// 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)
  }
}

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

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

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

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

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

      if let metadata::Data::StreamInfo(_) = block.data {
        *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) -> bool
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state    = ParserState::Header;
  let mut is_error = false;

  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(_)                   => {
        is_error = true;

        break;
      }
    }
  }

  is_error
}

#[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);
  }
}
<commit_msg>Change to using more clearer `is_stream_info`<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::{self, Metadata, metadata_parser};

/// 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>;
}

// 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)
  }
}

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

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

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

    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) -> bool
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state    = ParserState::Header;
  let mut is_error = false;

  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(_)                   => {
        is_error = true;

        break;
      }
    }
  }

  is_error
}

#[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);
  }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use serialize::json;
use serialize::json::{ToJson};

// masks for pulling nibbles out of bytes
const BYTE_WIDTH: uint = 8;
const U4_LOW:     u8   = 0b00001111;
const U4_HIGH:    u8   = 0b11110000;

/// If the CPU enters the `Halt` state then any additional ticks will result in
/// the program exhibiting undefined behavior.
///
#[deriving(PartialEq,Show)]
pub enum CpuState {
	Continue,
	Halt,
}

/// The P150 virtual machine
/// Represents all information the CPU needs to continue executing a
/// program stored in its main memory.
pub struct P150Cpu {
	ip:  u8,
	ir: u16,

	reg: [u8, ..16],
	mem: [u8, ..256],
}

impl P150Cpu {
	/// Initializes the P150 CPU
	///
	/// NOTE: This implementation 0s memory; but this is not guaranteed
	/// by the machine specification.
	///
	/// Programs MUST start at memory address 0x00
	pub fn new() -> P150Cpu {
		P150Cpu {
			ip:  0x00,
			ir:  0x0000,

			reg: [0u8, ..16],
			mem: [0u8, ..256],
		}
	}

	pub fn js_dump(&self) -> json::Json {
		let mut dict = HashMap::new();

		dict.insert(format!("ip"), self.ip.to_json());
		dict.insert(format!("ir"), self.ir.to_json());
		dict.insert(format!("reg"), self.reg.to_json());
		dict.insert(format!("mem"), self.mem.to_json());

		return dict.to_json();
	}

	#[cfg(test)]
	fn get_reg(&self) -> &[u8] { self.reg }

	/// Read an array of instructions into main memory
	/// This reads two bytes at a time from the `memory` array
	/// and loads them into the P150s RAM bank, starting from address 0.
	pub fn init_mem(&mut self, memory: &[u16]) {
		assert!(memory.len() <= (256 / 2)); // program cannot be larger than memory
		let mut next_cell = 0x00;

		// zero memory
		self.ip  = 0;
		self.ir  = 0;
		self.mem = [0, ..256];
		for op in memory.iter() {
			let byte_1 = (*op >> 8) as u8;
			let byte_2 = *op as u8;

			self.mem[next_cell]     = byte_1;
			self.mem[next_cell + 1] = byte_2;
			next_cell += 2
		}
	}

	/// Runs the entire fetch, execute, decode cycle against the current IP
	pub fn tick(&mut self) -> CpuState {
		self.fetch();

		// decode & execute
		let op = (self.ir >> 12) as u8;
		match op {
			0x0   => { // MLOAD
				let rloc_o0 = lo_nibble((self.ir >> 8) as u8);
				let mloc_i0 = self.ir as u8;

				self.reg[rloc_o0 as uint] = self.mem[mloc_i0 as uint];
				Continue
			},

			0x1   => { // RSET
				let rloc = lo_nibble((self.ir >> 8) as u8);  // lower nibble of first byte
				let rval = self.ir as u8;                    // value is entire second byte

				self.reg[rloc as uint] = rval;               // store value in register
				Continue
			},

			0x2   => { // MSTOR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let mloc_o0 = self.ir as u8;

				self.mem[mloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x3   => { // RMOV
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_o0 = hi_nibble(self.ir as u8);

				debug!("moving from {:02X} to {:02X}", rloc_i0, rloc_o0)
				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x4   => { // ADDB
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);   // first input: lower nibble of first byte
				let rloc_i1 = hi_nibble(self.ir as u8);          // second input: upper nibble of second byte
				let rloc_o0 = lo_nibble(self.ir as u8);          // output: lower nibble of second byte

				self.reg[rloc_o0 as uint] =
					((self.reg[rloc_i0 as uint] as i8) + (self.reg[rloc_i1 as uint]as i8)) as u8;
				Continue
			},

			0x6   => { // OR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] | self.reg[rloc_i1 as uint];
				Continue
			},

			0x7   => { // AND
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] & self.reg[rloc_i1 as uint];
				Continue
			},

			0x8   => { // XOR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] ^ self.reg[rloc_i1 as uint];
				Continue
			},

			0x9   => { // ROT
				// LHS shifts <width> bits off the (left) end of the bitstring
				// RHS shifts the bitstring to the right until only the bits which fell off remain.
				//   LHS is the remaining MSB bits; RHS is the remaining LSB bits
				//   ∴ LHS <OR> RHS provides a rotated bitstring
				//
				let rloc_i0   = lo_nibble((self.ir >> 8) as u8) as uint;          // register is first nibble ...
				let swidth    = (hi_nibble(self.ir as u8) & 0b0000_0111) as uint; // last three bytes of second nibble ...
				self.reg[rloc_i0 as uint] = (self.reg[rloc_i0] << swidth) | (self.reg[rloc_i0] >> (BYTE_WIDTH - swidth));

				Continue
			},

			0xA   => { // JMPEQ
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let next_ip = self.ir as u8;

				if self.reg[rloc_i0 as uint] == self.reg[0] { self.ip = next_ip }
				Continue
			},

			0xB   => { Halt },
			_     => { debug!("halt, cpu on fire: {}", op); Halt },
		}
	}

	/// Load the instruction at `IP` and advance the pointer by two bytes.
	/// The instruction is packed into a single `u16` and stored in the instruction register.
	fn fetch(&mut self) {
		// fetch two bytes from PC
		let byte_1 = self.mem[(self.ip+0) as uint];
		let byte_2 = self.mem[(self.ip+1) as uint];

		self.ir  = (byte_1 as u16 << 8) | (byte_2 as u16); // load byets into IR
		self.ip += 2;                                      // increment instruction pointer

		debug!("IR set to 0x{:04X} ({:02X},{:02X})", self.ir, byte_1, byte_2)
	}
}

/// Take the lower nibble of a byte
fn lo_nibble(byte: u8) -> u8 {
	(byte & U4_LOW)
}

/// Take the upper nibble of a byte and shift it
/// towards the least significant bits.
fn hi_nibble(byte: u8) -> u8 {
	(byte & U4_HIGH) >> 4
}

#[test]
fn test_hammer_time() {
	// cpu should stop after 1 tick of this program
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0xB000]);

	assert_eq!(cpu.tick(), Halt)
}

#[test]
fn test_registers() {
	// cpu should set, move registers accordingly
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1110, 0x3130, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x3], 16)
}

#[test]
fn test_memory() {
	// memory sets and memory stores should read back successfully
	// uninitialized registers should not match initialized registers
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1120, 0x1330, 0x2140, 0x0240, 0xB000]);
	boot(&mut cpu);

	assert!(cpu.get_reg()[0x1] == cpu.get_reg()[0x2]);
	assert!(cpu.get_reg()[0x1] != cpu.get_reg()[0x3]);
}

#[test]
fn test_bin() {
	// tests the various binary operations against their rustc counterparts.
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1121, 0x1222, 0x6123, 0x7124, 0x8125, 0xB000]);
	boot(&mut cpu);

	assert!(cpu.get_reg()[0x3] == (0x21 | 0x22));
	assert!(cpu.get_reg()[0x4] == (0x21 & 0x22));
	assert!(cpu.get_reg()[0x5] == (0x21 ^ 0x22));
}

#[test]
fn test_math() {
	// tests basic 2s comp. addition
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1120, 0x120A, 0x4123, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x3], cpu.get_reg()[0x1] + cpu.get_reg()[0x2]);
	assert_eq!(cpu.get_reg()[0x3], 0x20 + 0x0A);
}

#[test]
fn test_branch() {
	// checks that the program branches; skipping a halt and setting a status register
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1021, 0x1121, 0xA108, 0xB000, 0x122A, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x2], 0x2A)
}

#[test]
fn test_shift() {
	// checks that the program rotates a single nibble 4 places
	// this should move a single hex digit from the lhs to the rhs.
	//
	// NOTE: shifting 12 bits (12 - 8) and 4 bits should be equivalent.
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x10B0, 0x11B0, 0x90C0, 0x9140, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x0], 0x0B);
	assert_eq!(cpu.get_reg()[0x1], 0x0B);
}

#[cfg(test)]
fn boot(cpu: &mut P150Cpu) {
	loop {
		if cpu.tick() == Halt { break; }
	}
}

<commit_msg>Change direction of shift; also test both directions of shift.<commit_after>use std::collections::HashMap;
use serialize::json;
use serialize::json::{ToJson};

// masks for pulling nibbles out of bytes
const BYTE_WIDTH: uint = 8;
const U4_LOW:     u8   = 0b00001111;
const U4_HIGH:    u8   = 0b11110000;

/// If the CPU enters the `Halt` state then any additional ticks will result in
/// the program exhibiting undefined behavior.
///
#[deriving(PartialEq,Show)]
pub enum CpuState {
	Continue,
	Halt,
}

/// The P150 virtual machine
/// Represents all information the CPU needs to continue executing a
/// program stored in its main memory.
pub struct P150Cpu {
	ip:  u8,
	ir: u16,

	reg: [u8, ..16],
	mem: [u8, ..256],
}

impl P150Cpu {
	/// Initializes the P150 CPU
	///
	/// NOTE: This implementation 0s memory; but this is not guaranteed
	/// by the machine specification.
	///
	/// Programs MUST start at memory address 0x00
	pub fn new() -> P150Cpu {
		P150Cpu {
			ip:  0x00,
			ir:  0x0000,

			reg: [0u8, ..16],
			mem: [0u8, ..256],
		}
	}

	pub fn js_dump(&self) -> json::Json {
		let mut dict = HashMap::new();

		dict.insert(format!("ip"), self.ip.to_json());
		dict.insert(format!("ir"), self.ir.to_json());
		dict.insert(format!("reg"), self.reg.to_json());
		dict.insert(format!("mem"), self.mem.to_json());

		return dict.to_json();
	}

	#[cfg(test)]
	fn get_reg(&self) -> &[u8] { self.reg }

	/// Read an array of instructions into main memory
	/// This reads two bytes at a time from the `memory` array
	/// and loads them into the P150s RAM bank, starting from address 0.
	pub fn init_mem(&mut self, memory: &[u16]) {
		assert!(memory.len() <= (256 / 2)); // program cannot be larger than memory
		let mut next_cell = 0x00;

		// zero memory
		self.ip  = 0;
		self.ir  = 0;
		self.mem = [0, ..256];
		for op in memory.iter() {
			let byte_1 = (*op >> 8) as u8;
			let byte_2 = *op as u8;

			self.mem[next_cell]     = byte_1;
			self.mem[next_cell + 1] = byte_2;
			next_cell += 2
		}
	}

	/// Runs the entire fetch, execute, decode cycle against the current IP
	pub fn tick(&mut self) -> CpuState {
		self.fetch();

		// decode & execute
		let op = (self.ir >> 12) as u8;
		match op {
			0x0   => { // MLOAD
				let rloc_o0 = lo_nibble((self.ir >> 8) as u8);
				let mloc_i0 = self.ir as u8;

				self.reg[rloc_o0 as uint] = self.mem[mloc_i0 as uint];
				Continue
			},

			0x1   => { // RSET
				let rloc = lo_nibble((self.ir >> 8) as u8);  // lower nibble of first byte
				let rval = self.ir as u8;                    // value is entire second byte

				self.reg[rloc as uint] = rval;               // store value in register
				Continue
			},

			0x2   => { // MSTOR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let mloc_o0 = self.ir as u8;

				self.mem[mloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x3   => { // RMOV
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_o0 = hi_nibble(self.ir as u8);

				debug!("moving from {:02X} to {:02X}", rloc_i0, rloc_o0)
				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x4   => { // ADDB
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);   // first input: lower nibble of first byte
				let rloc_i1 = hi_nibble(self.ir as u8);          // second input: upper nibble of second byte
				let rloc_o0 = lo_nibble(self.ir as u8);          // output: lower nibble of second byte

				self.reg[rloc_o0 as uint] =
					((self.reg[rloc_i0 as uint] as i8) + (self.reg[rloc_i1 as uint]as i8)) as u8;
				Continue
			},

			0x6   => { // OR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] | self.reg[rloc_i1 as uint];
				Continue
			},

			0x7   => { // AND
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] & self.reg[rloc_i1 as uint];
				Continue
			},

			0x8   => { // XOR
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let rloc_i1 = hi_nibble(self.ir as u8);
				let rloc_o0 = lo_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] ^ self.reg[rloc_i1 as uint];
				Continue
			},

			0x9   => { // ROT
				// LHS shifts <width> bits off the (left) end of the bitstring
				// RHS shifts the bitstring to the right until only the bits which fell off remain.
				//   LHS is the remaining MSB bits; RHS is the remaining LSB bits
				//   ∴ LHS <OR> RHS provides a rotated bitstring
				//
				let rloc_i0   = lo_nibble((self.ir >> 8) as u8) as uint;          // register is first nibble ...
				let swidth    = (hi_nibble(self.ir as u8) & 0b0000_0111) as uint; // last three bytes of second nibble ...
				self.reg[rloc_i0 as uint] = (self.reg[rloc_i0] >> swidth) | (self.reg[rloc_i0] << (BYTE_WIDTH - swidth));

				Continue
			},

			0xA   => { // JMPEQ
				let rloc_i0 = lo_nibble((self.ir >> 8) as u8);
				let next_ip = self.ir as u8;

				if self.reg[rloc_i0 as uint] == self.reg[0] { self.ip = next_ip }
				Continue
			},

			0xB   => { Halt },
			_     => { debug!("halt, cpu on fire: {}", op); Halt },
		}
	}

	/// Load the instruction at `IP` and advance the pointer by two bytes.
	/// The instruction is packed into a single `u16` and stored in the instruction register.
	fn fetch(&mut self) {
		// fetch two bytes from PC
		let byte_1 = self.mem[(self.ip+0) as uint];
		let byte_2 = self.mem[(self.ip+1) as uint];

		self.ir  = (byte_1 as u16 << 8) | (byte_2 as u16); // load byets into IR
		self.ip += 2;                                      // increment instruction pointer

		debug!("IR set to 0x{:04X} ({:02X},{:02X})", self.ir, byte_1, byte_2)
	}
}

/// Take the lower nibble of a byte
fn lo_nibble(byte: u8) -> u8 {
	(byte & U4_LOW)
}

/// Take the upper nibble of a byte and shift it
/// towards the least significant bits.
fn hi_nibble(byte: u8) -> u8 {
	(byte & U4_HIGH) >> 4
}

#[test]
fn test_hammer_time() {
	// cpu should stop after 1 tick of this program
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0xB000]);

	assert_eq!(cpu.tick(), Halt)
}

#[test]
fn test_registers() {
	// cpu should set, move registers accordingly
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1110, 0x3130, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x3], 16)
}

#[test]
fn test_memory() {
	// memory sets and memory stores should read back successfully
	// uninitialized registers should not match initialized registers
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1120, 0x1330, 0x2140, 0x0240, 0xB000]);
	boot(&mut cpu);

	assert!(cpu.get_reg()[0x1] == cpu.get_reg()[0x2]);
	assert!(cpu.get_reg()[0x1] != cpu.get_reg()[0x3]);
}

#[test]
fn test_bin() {
	// tests the various binary operations against their rustc counterparts.
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1121, 0x1222, 0x6123, 0x7124, 0x8125, 0xB000]);
	boot(&mut cpu);

	assert!(cpu.get_reg()[0x3] == (0x21 | 0x22));
	assert!(cpu.get_reg()[0x4] == (0x21 & 0x22));
	assert!(cpu.get_reg()[0x5] == (0x21 ^ 0x22));
}

#[test]
fn test_math() {
	// tests basic 2s comp. addition
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1120, 0x120A, 0x4123, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x3], cpu.get_reg()[0x1] + cpu.get_reg()[0x2]);
	assert_eq!(cpu.get_reg()[0x3], 0x20 + 0x0A);
}

#[test]
fn test_branch() {
	// checks that the program branches; skipping a halt and setting a status register
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x1021, 0x1121, 0xA108, 0xB000, 0x122A, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x2], 0x2A)
}

#[test]
fn test_shift() {
	// checks that the program rotates a single nibble 4 places
	// this should move a single hex digit from the lhs to the rhs.
	//
	// NOTE: shifting 12 bits (12 - 8) and 4 bits should be equivalent.
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x10B0, 0x11B0, 0x90C0, 0x9140, 0xB000]);
	boot(&mut cpu);

	assert_eq!(cpu.get_reg()[0x0], 0x0B);
	assert_eq!(cpu.get_reg()[0x1], 0x0B);
}

#[test]
fn test_shift_right() {
	// checks that the program rotates a single nibble 3 places.
	// this arbitrary shift tests the directionality of the shift;
	//   which should be TO THE RIGHT.
	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x100C, 0x9030, 0xB000]);
	boot(&mut cpu);

	// 0b0000_1100 3-> == 0b1000_0001
	// 0x0C               0x81
	assert_eq!(cpu.get_reg()[0x0], 0x81);
}

#[test]
#[should_fail]
fn test_shift_left() {
	// checks that the program rotates a single nibble 3 places.
	// this arbitrary shift tests the directionality of the shift;
	//   this is the CONVERSE to the test above.
	//

	let mut cpu = P150Cpu::new();
	cpu.init_mem([0x100C, 0x9030, 0xB000]);
	boot(&mut cpu);

	// 0b0000_1100 <-3 == 0b0110_0000
	// 0x0C               0x60
	assert_eq!(cpu.get_reg()[0x0], 0x60);
}

#[cfg(test)]
fn boot(cpu: &mut P150Cpu) {
	loop {
		if cpu.tick() == Halt { break; }
	}
}

<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![crate_name = "grust_Gio_2_0"]
#![crate_type = "lib"]

#![allow(trivial_numeric_casts)]

#[macro_use]
extern crate grust;

#[macro_use]
#[no_link]
extern crate bitflags;

extern crate gio_2_0_sys as ffi;
extern crate glib_2_0_sys as glib_ffi;
extern crate gobject_2_0_sys as gobject_ffi;
extern crate grust_GLib_2_0 as glib;
extern crate grust_GObject_2_0 as gobject;

use grust::enumeration;
use grust::enumeration::IntrospectedEnum as _grust_IntrospectedEnumTrait;
use grust::error;
use grust::gstr;
use grust::gtype::GType;
use grust::object;
use grust::quark;
use grust::refcount;
use grust::types::{gint, gpointer};
use grust::wrap;

use std::fmt;
use std::mem;
use std::ptr;
use std::result;

#[repr(C)]
pub struct AsyncResult {
    raw: ffi::GAsyncResult
}

unsafe impl wrap::Wrapper for AsyncResult {
    type Raw = ffi::GAsyncResult;
}

#[repr(C)]
pub struct File {
    raw: ffi::GFile
}

unsafe impl wrap::Wrapper for File {
    type Raw = ffi::GFile;
}

#[repr(C)]
pub struct Cancellable {
    raw: ffi::GCancellable
}

unsafe impl Send for Cancellable { }
unsafe impl Sync for Cancellable { }
unsafe impl wrap::Wrapper for Cancellable {
    type Raw = ffi::GCancellable;
}

#[repr(C)]
pub struct InputStream {
    raw: ffi::GInputStream
}

unsafe impl wrap::Wrapper for InputStream {
    type Raw = ffi::GInputStream;
}

#[repr(C)]
pub struct FileInputStream {
    raw: ffi::GFileInputStream
}

unsafe impl wrap::Wrapper for FileInputStream {
    type Raw = ffi::GFileInputStream;
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(C)]
pub enum IOErrorEnum {
    Failed = 0,
    NotFound = 1,
    Exists = 2,
    // ...
}

impl enumeration::IntrospectedEnum for IOErrorEnum {

    fn from_int(v: gint) -> Result<Self, enumeration::UnknownValue> {
        match v {
            0 => Ok(IOErrorEnum::Failed),
            1 => Ok(IOErrorEnum::NotFound),
            2 => Ok(IOErrorEnum::Exists),
            _ => Err(enumeration::UnknownValue(v))
        }
    }

    fn to_int(&self) -> gint {
        *self as gint
    }

    fn name(&self) -> &'static str {
        match *self {
            IOErrorEnum::Failed => "failed",
            IOErrorEnum::NotFound => "not-found",
            IOErrorEnum::Exists   => "exists",
            // ...
        }
    }
}

impl enumeration::EnumType for IOErrorEnum {
    fn get_type() -> GType {
        unsafe { GType::from_raw(ffi::g_io_error_enum_get_type()) }
    }
}

impl error::Domain for IOErrorEnum {
    fn domain() -> quark::Quark {
        g_static_quark!(b"g-io-error-quark\0")
    }
}

impl fmt::Display for IOErrorEnum {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.name())
    }
}

pub mod flags {

    pub mod file_attribute_info {
        use grust::flags::prelude::*;
        use ffi;
        use std::fmt;

        bitflags! {
            flags Flags: guint {
                const NONE            = 0,
                const COPY_WITH_FILE  = 1,
                const COPY_WHEN_MOVED = 2,
            }
        }

        impl IntrospectedFlags for Flags {

            fn from_uint(v: guint) -> Result<Flags, UnknownFlags> {
                Flags::from_bits(v)
                    .ok_or_else(|| UnknownFlags::new(v, Flags::all().bits()))
            }

            #[inline]
            fn to_uint(&self) -> guint {
                self.bits()
            }
        }

        impl FlagsType for Flags {
            fn get_type() -> GType {
                unsafe {
                    let raw = ffi::g_file_attribute_info_flags_get_type();
                    GType::from_raw(raw)
                }
            }
        }

        impl fmt::Debug for Flags {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                const FLAG_INFO: &'static [(Flags, &'static str)] = &[
                    (COPY_WITH_FILE,  "COPY_WITH_FILE"),
                    (COPY_WHEN_MOVED, "COPY_WHEN_MOVED")
                ];
                let mut contents = String::new();
                for &(flag, name) in FLAG_INFO.iter() {
                    if self.contains(flag) {
                        if contents.is_empty() {
                            contents.push_str(name);
                        } else {
                            contents.push('|');
                            contents.push_str(name);
                        }
                    }
                }
                write!(f, "FileAttributeInfoFlags({})", contents)
            }
        }
    }
}

pub use flags::file_attribute_info::Flags as FileAttributeInfoFlags;

mod async {
    use ffi;
    use gobject_ffi;
    use gobject;

    use grust::types::gpointer;
    use grust::wrap;
    use std::mem;

    pub extern "C" fn async_ready_callback<F>(source_object: *mut gobject_ffi::GObject,
                                              res: *mut ffi::GAsyncResult,
                                              user_data: gpointer)
        where F: FnOnce(&gobject::Object, &super::AsyncResult)
    {
        let cb: Box<F> = unsafe { mem::transmute(user_data) };
        let arg1 = unsafe { wrap::from_raw::<gobject::Object>(source_object) };
        let arg2 = unsafe { wrap::from_raw::<super::AsyncResult>(res) };
        cb(arg1, arg2);
    }
}

pub mod cast {
    use grust::object;

    use gobject;

    pub trait AsAsyncResult {
        fn as_async_result(&self) -> &super::AsyncResult;
    }

    impl<T> AsAsyncResult for T where T: object::Upcast<super::AsyncResult> {

        #[inline]
        fn as_async_result(&self) -> &super::AsyncResult {
            self.upcast()
        }
    }

    pub trait AsCancellable : gobject::cast::AsObject {
        fn as_cancellable(&self) -> &super::Cancellable;
    }

    impl<T> AsCancellable for T
        where T: object::Upcast<super::Cancellable>,
              T: object::Upcast<gobject::Object>
    {
        #[inline]
        fn as_cancellable(&self) -> &super::Cancellable {
            self.upcast()
        }
    }

    pub trait AsInputStream : gobject::cast::AsObject {
        fn as_input_stream(&self) -> &super::InputStream;
    }

    impl<T> AsInputStream for T
        where T: object::Upcast<super::InputStream>,
              T: object::Upcast<gobject::Object>
    {
        #[inline]
        fn as_input_stream(&self) -> &super::InputStream {
            self.upcast()
        }
    }

    pub trait AsFileInputStream : AsInputStream {
        fn as_file_input_stream(&self) -> &super::FileInputStream;
    }

    impl<T> AsFileInputStream for T
        where T: object::Upcast<super::FileInputStream>,
              T: object::Upcast<super::InputStream>,
              T: object::Upcast<gobject::Object>
    {
        #[inline]
        fn as_file_input_stream(&self) -> &super::FileInputStream {
            self.upcast()
        }
    }

    pub trait AsFile {
        fn as_file(&self) -> &super::File;
    }

    impl<T> AsFile for T where T: object::Upcast<super::File> {

        #[inline]
        fn as_file(&self) -> &super::File {
            self.upcast()
        }
    }
}

impl File {

    pub fn new_for_path(path: &gstr::Utf8) -> refcount::Ref<File> {
        unsafe {
            let ret = ffi::g_file_new_for_path(path.as_ptr());
            refcount::Ref::from_raw(ret)
        }
    }

    pub fn get_path(&self) -> gstr::OwnedGStr {
        unsafe {
            use grust::wrap::Wrapper;
            let ret = ffi::g_file_get_path(self.as_mut_ptr());
            gstr::OwnedGStr::from_ptr(ret)
        }
    }

    pub fn read_async<F>(&self,
                         io_priority: gint,
                         cancellable: Option<&Cancellable>,
                         callback: F)
        where F: FnOnce(&gobject::Object, &AsyncResult),
              F: 'static
    {
        unsafe {
            use grust::wrap::Wrapper;
            let self_raw = self.as_mut_ptr();
            let cancellable = {
                match cancellable {
                    Some(c) => c.as_mut_ptr(),
                    None    => std::ptr::null_mut()
                }
            };
            let callback: gpointer = mem::transmute(Box::new(callback));

            ffi::g_file_read_async(self_raw,
                                   io_priority,
                                   cancellable,
                                   async::async_ready_callback::<F>,
                                   callback);
        }
    }

    pub fn read_finish(&self, res: &AsyncResult)
                      -> result::Result<refcount::Ref<FileInputStream>,
                                        error::Error> {
        let mut err: *mut glib_ffi::GError = ptr::null_mut();
        let ret = unsafe {
            use grust::wrap::Wrapper;
            ffi::g_file_read_finish(self.as_mut_ptr(),
                                    res.as_mut_ptr(),
                                    &mut err)
        };
        if err.is_null() {
            Ok(unsafe { refcount::Ref::from_raw(ret) })
        } else {
            Err(unsafe { error::Error::from_raw(err) })
        }
    }
}

unsafe impl object::ObjectType for AsyncResult {
    fn get_type() -> GType {
        unsafe {
            GType::from_raw(ffi::g_async_result_get_type())
        }
    }
}

unsafe impl object::ObjectType for File {
    fn get_type() -> GType {
        unsafe {
            GType::from_raw(ffi::g_file_get_type())
        }
    }
}

unsafe impl object::ObjectType for InputStream {
    fn get_type() -> GType {
        unsafe {
            GType::from_raw(ffi::g_input_stream_get_type())
        }
    }
}

unsafe impl object::ObjectType for FileInputStream {
    fn get_type() -> GType {
        unsafe {
            GType::from_raw(ffi::g_file_input_stream_get_type())
        }
    }
}

impl object::Upcast<gobject::Object> for Cancellable {

    #[inline]
    fn upcast(&self) -> &gobject::Object {
        unsafe {
            wrap::from_raw(&self.raw.parent_instance)
        }
    }
}

impl object::Upcast<gobject::Object> for InputStream {

    #[inline]
    fn upcast(&self) -> &gobject::Object {
        unsafe {
            wrap::from_raw(&self.raw.parent_instance)
        }
    }
}

impl object::Upcast<InputStream> for FileInputStream {

    #[inline]
    fn upcast(&self) -> &InputStream {
        unsafe {
            wrap::from_raw(&self.raw.parent_instance)
        }
    }
}

impl object::Upcast<gobject::Object> for FileInputStream {

    #[inline]
    fn upcast(&self) -> &gobject::Object {
        use cast::AsInputStream;
        self.as_input_stream().upcast()
    }
}
<commit_msg>Added Send bound to async closures<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![crate_name = "grust_Gio_2_0"]
#![crate_type = "lib"]

#![allow(trivial_numeric_casts)]

#[macro_use]
extern crate grust;

#[macro_use]
#[no_link]
extern crate bitflags;

extern crate gio_2_0_sys as ffi;
extern crate glib_2_0_sys as glib_ffi;
extern crate gobject_2_0_sys as gobject_ffi;
extern crate grust_GLib_2_0 as glib;
extern crate grust_GObject_2_0 as gobject;

use grust::enumeration;
use grust::enumeration::IntrospectedEnum as _grust_IntrospectedEnumTrait;
use grust::error;
use grust::gstr;
use grust::gtype::GType;
use grust::object;
use grust::quark;
use grust::refcount;
use grust::types::{gint, gpointer};
use grust::wrap;

use std::fmt;
use std::mem;
use std::ptr;
use std::result;

#[repr(C)]
pub struct AsyncResult {
    raw: ffi::GAsyncResult
}

unsafe impl wrap::Wrapper for AsyncResult {
    type Raw = ffi::GAsyncResult;
}

#[repr(C)]
pub struct File {
    raw: ffi::GFile
}

unsafe impl wrap::Wrapper for File {
    type Raw = ffi::GFile;
}

#[repr(C)]
pub struct Cancellable {
    raw: ffi::GCancellable
}

unsafe impl Send for Cancellable { }
unsafe impl Sync for Cancellable { }
unsafe impl wrap::Wrapper for Cancellable {
    type Raw = ffi::GCancellable;
}

#[repr(C)]
pub struct InputStream {
    raw: ffi::GInputStream
}

unsafe impl wrap::Wrapper for InputStream {
    type Raw = ffi::GInputStream;
}

#[repr(C)]
pub struct FileInputStream {
    raw: ffi::GFileInputStream
}

unsafe impl wrap::Wrapper for FileInputStream {
    type Raw = ffi::GFileInputStream;
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(C)]
pub enum IOErrorEnum {
    Failed = 0,
    NotFound = 1,
    Exists = 2,
    // ...
}

impl enumeration::IntrospectedEnum for IOErrorEnum {

    fn from_int(v: gint) -> Result<Self, enumeration::UnknownValue> {
        match v {
            0 => Ok(IOErrorEnum::Failed),
            1 => Ok(IOErrorEnum::NotFound),
            2 => Ok(IOErrorEnum::Exists),
            _ => Err(enumeration::UnknownValue(v))
        }
    }

    fn to_int(&self) -> gint {
        *self as gint
    }

    fn name(&self) -> &'static str {
        match *self {
            IOErrorEnum::Failed => "failed",
            IOErrorEnum::NotFound => "not-found",
            IOErrorEnum::Exists   => "exists",
            // ...
        }
    }
}

impl enumeration::EnumType for IOErrorEnum {
    fn get_type() -> GType {
        unsafe { GType::from_raw(ffi::g_io_error_enum_get_type()) }
    }
}

impl error::Domain for IOErrorEnum {
    fn domain() -> quark::Quark {
        g_static_quark!(b"g-io-error-quark\0")
    }
}

impl fmt::Display for IOErrorEnum {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.name())
    }
}

pub mod flags {

    pub mod file_attribute_info {
        use grust::flags::prelude::*;
        use ffi;
        use std::fmt;

        bitflags! {
            flags Flags: guint {
                const NONE            = 0,
                const COPY_WITH_FILE  = 1,
                const COPY_WHEN_MOVED = 2,
            }
        }

        impl IntrospectedFlags for Flags {

            fn from_uint(v: guint) -> Result<Flags, UnknownFlags> {
                Flags::from_bits(v)
                    .ok_or_else(|| UnknownFlags::new(v, Flags::all().bits()))
            }

            #[inline]
            fn to_uint(&self) -> guint {
                self.bits()
            }
        }

        impl FlagsType for Flags {
            fn get_type() -> GType {
                unsafe {
                    let raw = ffi::g_file_attribute_info_flags_get_type();
                    GType::from_raw(raw)
                }
            }
        }

        impl fmt::Debug for Flags {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                const FLAG_INFO: &'static [(Flags, &'static str)] = &[
                    (COPY_WITH_FILE,  "COPY_WITH_FILE"),
                    (COPY_WHEN_MOVED, "COPY_WHEN_MOVED")
                ];
                let mut contents = String::new();
                for &(flag, name) in FLAG_INFO.iter() {
                    if self.contains(flag) {
                        if contents.is_empty() {
                            contents.push_str(name);
                        } else {
                            contents.push('|');
                            contents.push_str(name);
                        }
                    }
                }
                write!(f, "FileAttributeInfoFlags({})", contents)
            }
        }
    }
}

pub use flags::file_attribute_info::Flags as FileAttributeInfoFlags;

mod async {
    use ffi;
    use gobject_ffi;
    use gobject;

    use grust::types::gpointer;
    use grust::wrap;
    use std::mem;

    pub extern "C" fn async_ready_callback<F>(source_object: *mut gobject_ffi::GObject,
                                              res: *mut ffi::GAsyncResult,
                                              user_data: gpointer)
        where F: FnOnce(&gobject::Object, &super::AsyncResult)
    {
        let cb: Box<F> = unsafe { mem::transmute(user_data) };
        let arg1 = unsafe { wrap::from_raw::<gobject::Object>(source_object) };
        let arg2 = unsafe { wrap::from_raw::<super::AsyncResult>(res) };
        cb(arg1, arg2);
    }
}

pub mod cast {
    use grust::object;

    use gobject;

    pub trait AsAsyncResult {
        fn as_async_result(&self) -> &super::AsyncResult;
    }

    impl<T> AsAsyncResult for T where T: object::Upcast<super::AsyncResult> {

        #[inline]
        fn as_async_result(&self) -> &super::AsyncResult {
            self.upcast()
        }
    }

    pub trait AsCancellable : gobject::cast::AsObject {
        fn as_cancellable(&self) -> &super::Cancellable;
    }

    impl<T> AsCancellable for T
        where T: object::Upcast<super::Cancellable>,
              T: object::Upcast<gobject::Object>
    {
        #[inline]
        fn as_cancellable(&self) -> &super::Cancellable {
            self.upcast()
        }
    }

    pub trait AsInputStream : gobject::cast::AsObject {
        fn as_input_stream(&self) -> &super::InputStream;
    }

    impl<T> AsInputStream for T
        where T: object::Upcast<super::InputStream>,
              T: object::Upcast<gobject::Object>
    {
        #[inline]
        fn as_input_stream(&self) -> &super::InputStream {
            self.upcast()
        }
    }

    pub trait AsFileInputStream : AsInputStream {
        fn as_file_input_stream(&self) -> &super::FileInputStream;
    }

    impl<T> AsFileInputStream for T
        where T: object::Upcast<super::FileInputStream>,
              T: object::Upcast<super::InputStream>,
              T: object::Upcast<gobject::Object>
    {
        #[inline]
        fn as_file_input_stream(&self) -> &super::FileInputStream {
            self.upcast()
        }
    }

    pub trait AsFile {
        fn as_file(&self) -> &super::File;
    }

    impl<T> AsFile for T where T: object::Upcast<super::File> {

        #[inline]
        fn as_file(&self) -> &super::File {
            self.upcast()
        }
    }
}

impl File {

    pub fn new_for_path(path: &gstr::Utf8) -> refcount::Ref<File> {
        unsafe {
            let ret = ffi::g_file_new_for_path(path.as_ptr());
            refcount::Ref::from_raw(ret)
        }
    }

    pub fn get_path(&self) -> gstr::OwnedGStr {
        unsafe {
            use grust::wrap::Wrapper;
            let ret = ffi::g_file_get_path(self.as_mut_ptr());
            gstr::OwnedGStr::from_ptr(ret)
        }
    }

    pub fn read_async<F>(&self,
                         io_priority: gint,
                         cancellable: Option<&Cancellable>,
                         callback: F)
        where F: FnOnce(&gobject::Object, &AsyncResult),
              F: Send + 'static
    {
        unsafe {
            use grust::wrap::Wrapper;
            let self_raw = self.as_mut_ptr();
            let cancellable = {
                match cancellable {
                    Some(c) => c.as_mut_ptr(),
                    None    => std::ptr::null_mut()
                }
            };
            let callback: gpointer = mem::transmute(Box::new(callback));

            ffi::g_file_read_async(self_raw,
                                   io_priority,
                                   cancellable,
                                   async::async_ready_callback::<F>,
                                   callback);
        }
    }

    pub fn read_finish(&self, res: &AsyncResult)
                      -> result::Result<refcount::Ref<FileInputStream>,
                                        error::Error> {
        let mut err: *mut glib_ffi::GError = ptr::null_mut();
        let ret = unsafe {
            use grust::wrap::Wrapper;
            ffi::g_file_read_finish(self.as_mut_ptr(),
                                    res.as_mut_ptr(),
                                    &mut err)
        };
        if err.is_null() {
            Ok(unsafe { refcount::Ref::from_raw(ret) })
        } else {
            Err(unsafe { error::Error::from_raw(err) })
        }
    }
}

unsafe impl object::ObjectType for AsyncResult {
    fn get_type() -> GType {
        unsafe {
            GType::from_raw(ffi::g_async_result_get_type())
        }
    }
}

unsafe impl object::ObjectType for File {
    fn get_type() -> GType {
        unsafe {
            GType::from_raw(ffi::g_file_get_type())
        }
    }
}

unsafe impl object::ObjectType for InputStream {
    fn get_type() -> GType {
        unsafe {
            GType::from_raw(ffi::g_input_stream_get_type())
        }
    }
}

unsafe impl object::ObjectType for FileInputStream {
    fn get_type() -> GType {
        unsafe {
            GType::from_raw(ffi::g_file_input_stream_get_type())
        }
    }
}

impl object::Upcast<gobject::Object> for Cancellable {

    #[inline]
    fn upcast(&self) -> &gobject::Object {
        unsafe {
            wrap::from_raw(&self.raw.parent_instance)
        }
    }
}

impl object::Upcast<gobject::Object> for InputStream {

    #[inline]
    fn upcast(&self) -> &gobject::Object {
        unsafe {
            wrap::from_raw(&self.raw.parent_instance)
        }
    }
}

impl object::Upcast<InputStream> for FileInputStream {

    #[inline]
    fn upcast(&self) -> &InputStream {
        unsafe {
            wrap::from_raw(&self.raw.parent_instance)
        }
    }
}

impl object::Upcast<gobject::Object> for FileInputStream {

    #[inline]
    fn upcast(&self) -> &gobject::Object {
        use cast::AsInputStream;
        self.as_input_stream().upcast()
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]

use cocoa::foundation::NSUInteger;
use std::convert::{From, Into};
use sys::{MTLClearColor, MTLDispatchThreadgroupsIndirectArguments, MTLDrawIndexedPrimitivesIndirectArguments,
          MTLDrawPrimitivesIndirectArguments, MTLOrigin, MTLRegion, MTLScissorRect, MTLSize, MTLViewport};
use sys::{MTLClearColorMake, MTLOriginMake, MTLSizeMake};

#[derive(Clone, Copy, Default, Debug, PartialEq)]
pub struct ClearColor {
    pub red: f64,
    pub green: f64,
    pub blue: f64,
    pub alpha: f64
}

impl ClearColor {
    pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
        ClearColor {
            red: red,
            green: green,
            blue: blue,
            alpha: alpha
        }
    }
}

impl From<[f64; 4]> for ClearColor {
    fn from(slice: [f64; 4]) -> Self {
        ClearColor::new(slice[0], slice[1], slice[2], slice[3])
    }
}

impl From<(f64, f64, f64, f64)> for ClearColor {
    fn from((r, g, b, a): (f64, f64, f64, f64)) -> Self {
        ClearColor::new(r, g, b, a)
    }
}

impl From<MTLClearColor> for ClearColor {
    fn from(mtl_color: MTLClearColor) -> Self {
        ClearColor::new(mtl_color.red, mtl_color.green, mtl_color.blue, mtl_color.alpha)
    }
}

impl Into<MTLClearColor> for ClearColor {
    fn into(self) -> MTLClearColor {
        MTLClearColorMake(self.red, self.green, self.blue, self.alpha)
    }
}

#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
pub struct Origin {
    pub x: usize,
    pub y: usize,
    pub z: usize
}

impl Origin {
    pub fn new(x: usize, y: usize, z: usize) -> Self {
        Origin {
            x: x,
            y: y,
            z: z
        }
    }
}

impl From<[usize; 3]> for Origin {
    fn from(slice: [usize; 3]) -> Self {
        Origin::new(slice[0], slice[1], slice[2])
    }
}

impl From<(usize, usize, usize)> for Origin {
    fn from((x, y, z): (usize, usize, usize)) -> Self {
        Origin::new(x, y, z)
    }
}

impl From<MTLOrigin> for Origin {
    fn from(mtl_size: MTLOrigin) -> Self {
        Origin::new(mtl_size.x as usize, mtl_size.y as usize, mtl_size.z as usize)
    }
}

impl Into<MTLOrigin> for Origin {
    fn into(self) -> MTLOrigin {
        MTLOriginMake(self.x as NSUInteger, self.y as NSUInteger, self.z as NSUInteger)
    }
}

#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
pub struct Region {
    pub size: Size,
    pub origin: Origin
}

impl Region {
    pub fn from_parts(size: Size, origin: Origin) -> Self {
        Region {
            size: size,
            origin: origin
        }
    }

    pub fn new_1d(x: usize, width: usize) -> Self {
        let origin = Origin {x: x, y: 0, z: 0};
        let size = Size {width: width, height: 1, depth: 1};
        Region::from_parts(size, origin)
    }

    pub fn new_2d(x: usize, y: usize, width: usize, height: usize) -> Self {
        let origin = Origin {x: x, y: y, z: 0};
        let size = Size {width: width, height: height, depth: 1};
        Region::from_parts(size, origin)
    }

    pub fn new_3d(x: usize, y: usize, z: usize, width: usize, height: usize, depth: usize) -> Self {
        let origin = Origin {x: x, y: y, z: z};
        let size = Size {width: width, height: height, depth: depth};
        Region::from_parts(size, origin)
    }
}

impl From<MTLRegion> for Region {
    fn from(mtl_region: MTLRegion) -> Self {
        Region::from_parts(mtl_region.size.into(), mtl_region.origin.into())
    }
}

impl Into<MTLRegion> for Region {
    fn into(self) -> MTLRegion {
        MTLRegion {
            size: self.size.into(),
            origin: self.origin.into()
        }
    }
}

#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
pub struct ScissorRect {
    pub x: usize,
    pub y: usize,
    pub width: usize,
    pub height: usize
}

impl From<MTLScissorRect> for ScissorRect {
    fn from(mtl_scissor_rect: MTLScissorRect) -> Self {
        ScissorRect {
            x: mtl_scissor_rect.x as usize,
            y: mtl_scissor_rect.y as usize,
            width: mtl_scissor_rect.width as usize,
            height: mtl_scissor_rect.height as usize
        }
    }
}

impl Into<MTLScissorRect> for ScissorRect {
    fn into(self) -> MTLScissorRect {
        MTLScissorRect {
            x: self.x as NSUInteger,
            y: self.y as NSUInteger,
            width: self.width as NSUInteger,
            height: self.height as NSUInteger
        }
    }
}

#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
pub struct Size {
    pub width: usize,
    pub height: usize,
    pub depth: usize
}

impl Size {
    pub fn new(width: usize, height: usize, depth: usize) -> Self {
        Size {
            width: width,
            height: height,
            depth: depth
        }
    }
}

impl From<[usize; 3]> for Size {
    fn from(slice: [usize; 3]) -> Self {
        Size::new(slice[0], slice[1], slice[2])
    }
}

impl From<(usize, usize, usize)> for Size {
    fn from((w, h, d): (usize, usize, usize)) -> Self {
        Size::new(w, h, d)
    }
}

impl From<MTLSize> for Size {
    fn from(mtl_size: MTLSize) -> Self {
        Size::new(mtl_size.width as usize, mtl_size.height as usize, mtl_size.depth as usize)
    }
}

impl Into<MTLSize> for Size {
    fn into(self) -> MTLSize {
        MTLSizeMake(self.width as NSUInteger, self.height as NSUInteger, self.depth as NSUInteger)
    }
}

#[derive(Clone, Copy, Default, Debug, PartialEq)]
pub struct Viewport {
    /// The x coordinate of the upper-left corner of the viewport.
    pub origin_x: f64,

    /// The y coordinate of the upper-left corner of the viewport.
    pub origin_y: f64,

    /// The width of the viewport, in pixels.
    pub width: f64,

    /// The height of the viewport, in pixels.
    pub height: f64,

    /// The z coordinate of the near clipping plane of the viewport.
    pub znear: f64,

    /// The z coordinate of the far clipping plane of the viewport.
    pub zfar: f64
}

impl Viewport {
    pub fn new(ox: f64, oy: f64, w: f64, h: f64, znear: f64, zfar: f64) -> Self {
        Viewport {
            x_origin: ox,
            y_origin: oy,
            width: w,
            height: h,
            znear: znear,
            zfar: zfar
        }
    }
}

impl From<MTLViewport> for Viewport {
    fn from(mtl_viewport: MTLViewport) -> Self {
        Viewport::new(mtl_viewport.originX,
                      mtl_viewport.originY,
                      mtl_viewport.width,
                      mtl_viewport.height,
                      mtl_viewport.znear,
                      mtl_viewport.zfar)
    }
}

impl Into<MTLViewport> for Viewport {
    fn into(self) -> MTLViewport {
        MTLViewport {
            originX: self.x_origin,
            originY: self.y_origin,
            width: self.width,
            height: self.height,
            znear: self.znear,
            zfar: self.zfar
        }
    }
}
<commit_msg>Forgot to fix everything from last commit<commit_after>#![allow(unused_imports)]

use cocoa::foundation::NSUInteger;
use std::convert::{From, Into};
use sys::{MTLClearColor, MTLDispatchThreadgroupsIndirectArguments, MTLDrawIndexedPrimitivesIndirectArguments,
          MTLDrawPrimitivesIndirectArguments, MTLOrigin, MTLRegion, MTLScissorRect, MTLSize, MTLViewport};
use sys::{MTLClearColorMake, MTLOriginMake, MTLSizeMake};

#[derive(Clone, Copy, Default, Debug, PartialEq)]
pub struct ClearColor {
    pub red: f64,
    pub green: f64,
    pub blue: f64,
    pub alpha: f64
}

impl ClearColor {
    pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
        ClearColor {
            red: red,
            green: green,
            blue: blue,
            alpha: alpha
        }
    }
}

impl From<[f64; 4]> for ClearColor {
    fn from(slice: [f64; 4]) -> Self {
        ClearColor::new(slice[0], slice[1], slice[2], slice[3])
    }
}

impl From<(f64, f64, f64, f64)> for ClearColor {
    fn from((r, g, b, a): (f64, f64, f64, f64)) -> Self {
        ClearColor::new(r, g, b, a)
    }
}

impl From<MTLClearColor> for ClearColor {
    fn from(mtl_color: MTLClearColor) -> Self {
        ClearColor::new(mtl_color.red, mtl_color.green, mtl_color.blue, mtl_color.alpha)
    }
}

impl Into<MTLClearColor> for ClearColor {
    fn into(self) -> MTLClearColor {
        MTLClearColorMake(self.red, self.green, self.blue, self.alpha)
    }
}

#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
pub struct Origin {
    pub x: usize,
    pub y: usize,
    pub z: usize
}

impl Origin {
    pub fn new(x: usize, y: usize, z: usize) -> Self {
        Origin {
            x: x,
            y: y,
            z: z
        }
    }
}

impl From<[usize; 3]> for Origin {
    fn from(slice: [usize; 3]) -> Self {
        Origin::new(slice[0], slice[1], slice[2])
    }
}

impl From<(usize, usize, usize)> for Origin {
    fn from((x, y, z): (usize, usize, usize)) -> Self {
        Origin::new(x, y, z)
    }
}

impl From<MTLOrigin> for Origin {
    fn from(mtl_size: MTLOrigin) -> Self {
        Origin::new(mtl_size.x as usize, mtl_size.y as usize, mtl_size.z as usize)
    }
}

impl Into<MTLOrigin> for Origin {
    fn into(self) -> MTLOrigin {
        MTLOriginMake(self.x as NSUInteger, self.y as NSUInteger, self.z as NSUInteger)
    }
}

#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
pub struct Region {
    pub size: Size,
    pub origin: Origin
}

impl Region {
    pub fn from_parts(size: Size, origin: Origin) -> Self {
        Region {
            size: size,
            origin: origin
        }
    }

    pub fn new_1d(x: usize, width: usize) -> Self {
        let origin = Origin {x: x, y: 0, z: 0};
        let size = Size {width: width, height: 1, depth: 1};
        Region::from_parts(size, origin)
    }

    pub fn new_2d(x: usize, y: usize, width: usize, height: usize) -> Self {
        let origin = Origin {x: x, y: y, z: 0};
        let size = Size {width: width, height: height, depth: 1};
        Region::from_parts(size, origin)
    }

    pub fn new_3d(x: usize, y: usize, z: usize, width: usize, height: usize, depth: usize) -> Self {
        let origin = Origin {x: x, y: y, z: z};
        let size = Size {width: width, height: height, depth: depth};
        Region::from_parts(size, origin)
    }
}

impl From<MTLRegion> for Region {
    fn from(mtl_region: MTLRegion) -> Self {
        Region::from_parts(mtl_region.size.into(), mtl_region.origin.into())
    }
}

impl Into<MTLRegion> for Region {
    fn into(self) -> MTLRegion {
        MTLRegion {
            size: self.size.into(),
            origin: self.origin.into()
        }
    }
}

#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
pub struct ScissorRect {
    pub x: usize,
    pub y: usize,
    pub width: usize,
    pub height: usize
}

impl From<MTLScissorRect> for ScissorRect {
    fn from(mtl_scissor_rect: MTLScissorRect) -> Self {
        ScissorRect {
            x: mtl_scissor_rect.x as usize,
            y: mtl_scissor_rect.y as usize,
            width: mtl_scissor_rect.width as usize,
            height: mtl_scissor_rect.height as usize
        }
    }
}

impl Into<MTLScissorRect> for ScissorRect {
    fn into(self) -> MTLScissorRect {
        MTLScissorRect {
            x: self.x as NSUInteger,
            y: self.y as NSUInteger,
            width: self.width as NSUInteger,
            height: self.height as NSUInteger
        }
    }
}

#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
pub struct Size {
    pub width: usize,
    pub height: usize,
    pub depth: usize
}

impl Size {
    pub fn new(width: usize, height: usize, depth: usize) -> Self {
        Size {
            width: width,
            height: height,
            depth: depth
        }
    }
}

impl From<[usize; 3]> for Size {
    fn from(slice: [usize; 3]) -> Self {
        Size::new(slice[0], slice[1], slice[2])
    }
}

impl From<(usize, usize, usize)> for Size {
    fn from((w, h, d): (usize, usize, usize)) -> Self {
        Size::new(w, h, d)
    }
}

impl From<MTLSize> for Size {
    fn from(mtl_size: MTLSize) -> Self {
        Size::new(mtl_size.width as usize, mtl_size.height as usize, mtl_size.depth as usize)
    }
}

impl Into<MTLSize> for Size {
    fn into(self) -> MTLSize {
        MTLSizeMake(self.width as NSUInteger, self.height as NSUInteger, self.depth as NSUInteger)
    }
}

#[derive(Clone, Copy, Default, Debug, PartialEq)]
pub struct Viewport {
    /// The x coordinate of the upper-left corner of the viewport.
    pub origin_x: f64,

    /// The y coordinate of the upper-left corner of the viewport.
    pub origin_y: f64,

    /// The width of the viewport, in pixels.
    pub width: f64,

    /// The height of the viewport, in pixels.
    pub height: f64,

    /// The z coordinate of the near clipping plane of the viewport.
    pub znear: f64,

    /// The z coordinate of the far clipping plane of the viewport.
    pub zfar: f64
}

impl Viewport {
    pub fn new(ox: f64, oy: f64, w: f64, h: f64, znear: f64, zfar: f64) -> Self {
        Viewport {
            origin_x: ox,
            origin_y: oy,
            width: w,
            height: h,
            znear: znear,
            zfar: zfar
        }
    }
}

impl From<MTLViewport> for Viewport {
    fn from(mtl_viewport: MTLViewport) -> Self {
        Viewport::new(mtl_viewport.originX,
                      mtl_viewport.originY,
                      mtl_viewport.width,
                      mtl_viewport.height,
                      mtl_viewport.znear,
                      mtl_viewport.zfar)
    }
}

impl Into<MTLViewport> for Viewport {
    fn into(self) -> MTLViewport {
        MTLViewport {
            originX: self.origin_x,
            originY: self.origin_y,
            width: self.width,
            height: self.height,
            znear: self.znear,
            zfar: self.zfar
        }
    }
}
<|endoftext|>


<commit_before>use {Printer, With};
use direction::Direction;
use event::{Event, EventResult, Key};
use std::cell::RefCell;
use std::rc::Rc;
use theme::ColorStyle;
use vec::Vec2;
use view::View;

struct SharedState<T> {
    selection: usize,
    values: Vec<Rc<T>>,
}

impl<T> SharedState<T> {
    pub fn selection(&self) -> Rc<T> {
        self.values[self.selection].clone()
    }
}

/// Group to coordinate multiple radio buttons.
///
/// A `RadioGroup` is used to create and manage [`RadioButton`]s.
///
/// A `RadioGroup` can be cloned; it will keep pointing to the same group.
///
/// [`RadioButton`]: struct.RadioButton.html
#[derive(Clone)]
pub struct RadioGroup<T> {
    // Given to every child button
    state: Rc<RefCell<SharedState<T>>>,
}

impl<T> Default for RadioGroup<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T> RadioGroup<T> {
    /// Creates an empty group for radio buttons.
    pub fn new() -> Self {
        RadioGroup {
            state: Rc::new(RefCell::new(SharedState {
                selection: 0,
                values: Vec::new(),
            })),
        }
    }

    /// Adds a new button to the group.
    ///
    /// The button will display `label` next to it, and will embed `value`.
    pub fn button<S: Into<String>>(
        &mut self, value: T, label: S
    ) -> RadioButton<T> {
        let count = self.state.borrow().values.len();
        self.state.borrow_mut().values.push(Rc::new(value));
        RadioButton::new(self.state.clone(), count, label.into())
    }

    /// Returns the id of the selected button.
    ///
    /// Buttons are indexed in the order they are created, starting from 0.
    pub fn selected_id(&self) -> usize {
        self.state.borrow().selection
    }

    /// Returns the value associated with the selected button.
    pub fn selection(&self) -> Rc<T> {
        self.state.borrow().selection()
    }
}

impl RadioGroup<String> {
    /// Adds a button, using the label itself as value.
    pub fn button_str<S: Into<String>>(
        &mut self, text: S
    ) -> RadioButton<String> {
        let text = text.into();
        self.button(text.clone(), text)
    }
}

/// Variant of `Checkbox` arranged in group.
///
/// `RadioButton`s are managed by a [`RadioGroup`]. A single group can contain
/// several radio buttons, but only one button per group can be active at a
/// time.
///
/// `RadioButton`s are not created directly, but through
/// [`RadioGroup::button()`].
///
/// [`RadioGroup`]: struct.RadioGroup.html
/// [`RadioGroup::button()`]: struct.RadioGroup.html#method.button
pub struct RadioButton<T> {
    state: Rc<RefCell<SharedState<T>>>,
    id: usize,
    enabled: bool,
    label: String,
}

impl<T> RadioButton<T> {
    impl_enabled!(self.enabled);

    fn new(
        state: Rc<RefCell<SharedState<T>>>, id: usize, label: String
    ) -> Self {
        RadioButton {
            state: state,
            id: id,
            enabled: true,
            label: label,
        }
    }

    /// Returns `true` if this button is selected.
    pub fn is_selected(&self) -> bool {
        self.state.borrow().selection == self.id
    }

    /// Selects this button, un-selecting any other in the same group.
    pub fn select(&mut self) {
        self.state.borrow_mut().selection = self.id;
    }

    /// Selects this button, un-selecting any other in the same group.
    ///
    /// Chainable variant.
    pub fn selected(self) -> Self {
        self.with(Self::select)
    }

    fn draw_internal(&self, printer: &Printer) {
        printer.print((0, 0), "( )");
        if self.is_selected() {
            printer.print((1, 0), "X");
        }

        if !self.label.is_empty() {
            // We want the space to be highlighted if focused
            printer.print((3, 0), " ");
            printer.print((4, 0), &self.label);
        }
    }
}

impl<T> View for RadioButton<T> {
    fn required_size(&mut self, _: Vec2) -> Vec2 {
        if self.label.is_empty() {
            Vec2::new(3, 1)
        } else {
            Vec2::new(3 + 1 + self.label.len(), 1)
        }
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.enabled
    }

    fn draw(&self, printer: &Printer) {
        if self.enabled {
            printer.with_selection(
                printer.focused,
                |printer| self.draw_internal(printer),
            );
        } else {
            printer.with_color(
                ColorStyle::Secondary,
                |printer| self.draw_internal(printer),
            );
        }
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match event {
            Event::Key(Key::Enter) | Event::Char(' ') => {
                self.select();
                EventResult::Consumed(None)
            }
            _ => EventResult::Ignored,
        }
    }
}
<commit_msg>Add mouse support to radio view<commit_after>use {Printer, With};
use direction::Direction;
use event::{Event, EventResult, Key, MouseButton, MouseEvent};
use std::cell::RefCell;
use std::rc::Rc;
use theme::ColorStyle;
use vec::Vec2;
use view::View;

struct SharedState<T> {
    selection: usize,
    values: Vec<Rc<T>>,
}

impl<T> SharedState<T> {
    pub fn selection(&self) -> Rc<T> {
        self.values[self.selection].clone()
    }
}

/// Group to coordinate multiple radio buttons.
///
/// A `RadioGroup` is used to create and manage [`RadioButton`]s.
///
/// A `RadioGroup` can be cloned; it will keep pointing to the same group.
///
/// [`RadioButton`]: struct.RadioButton.html
#[derive(Clone)]
pub struct RadioGroup<T> {
    // Given to every child button
    state: Rc<RefCell<SharedState<T>>>,
}

impl<T> Default for RadioGroup<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T> RadioGroup<T> {
    /// Creates an empty group for radio buttons.
    pub fn new() -> Self {
        RadioGroup {
            state: Rc::new(RefCell::new(SharedState {
                selection: 0,
                values: Vec::new(),
            })),
        }
    }

    /// Adds a new button to the group.
    ///
    /// The button will display `label` next to it, and will embed `value`.
    pub fn button<S: Into<String>>(
        &mut self, value: T, label: S
    ) -> RadioButton<T> {
        let count = self.state.borrow().values.len();
        self.state.borrow_mut().values.push(Rc::new(value));
        RadioButton::new(self.state.clone(), count, label.into())
    }

    /// Returns the id of the selected button.
    ///
    /// Buttons are indexed in the order they are created, starting from 0.
    pub fn selected_id(&self) -> usize {
        self.state.borrow().selection
    }

    /// Returns the value associated with the selected button.
    pub fn selection(&self) -> Rc<T> {
        self.state.borrow().selection()
    }
}

impl RadioGroup<String> {
    /// Adds a button, using the label itself as value.
    pub fn button_str<S: Into<String>>(
        &mut self, text: S
    ) -> RadioButton<String> {
        let text = text.into();
        self.button(text.clone(), text)
    }
}

/// Variant of `Checkbox` arranged in group.
///
/// `RadioButton`s are managed by a [`RadioGroup`]. A single group can contain
/// several radio buttons, but only one button per group can be active at a
/// time.
///
/// `RadioButton`s are not created directly, but through
/// [`RadioGroup::button()`].
///
/// [`RadioGroup`]: struct.RadioGroup.html
/// [`RadioGroup::button()`]: struct.RadioGroup.html#method.button
pub struct RadioButton<T> {
    state: Rc<RefCell<SharedState<T>>>,
    id: usize,
    enabled: bool,
    label: String,
}

impl<T> RadioButton<T> {
    impl_enabled!(self.enabled);

    fn new(
        state: Rc<RefCell<SharedState<T>>>, id: usize, label: String
    ) -> Self {
        RadioButton {
            state: state,
            id: id,
            enabled: true,
            label: label,
        }
    }

    /// Returns `true` if this button is selected.
    pub fn is_selected(&self) -> bool {
        self.state.borrow().selection == self.id
    }

    /// Selects this button, un-selecting any other in the same group.
    pub fn select(&mut self) {
        self.state.borrow_mut().selection = self.id;
    }

    /// Selects this button, un-selecting any other in the same group.
    ///
    /// Chainable variant.
    pub fn selected(self) -> Self {
        self.with(Self::select)
    }

    fn draw_internal(&self, printer: &Printer) {
        printer.print((0, 0), "( )");
        if self.is_selected() {
            printer.print((1, 0), "X");
        }

        if !self.label.is_empty() {
            // We want the space to be highlighted if focused
            printer.print((3, 0), " ");
            printer.print((4, 0), &self.label);
        }
    }

    fn req_size(&self) -> Vec2 {
        if self.label.is_empty() {
            Vec2::new(3, 1)
        } else {
            Vec2::new(3 + 1 + self.label.len(), 1)
        }
    }
}

impl<T> View for RadioButton<T> {
    fn required_size(&mut self, _: Vec2) -> Vec2 {
        self.req_size()
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.enabled
    }

    fn draw(&self, printer: &Printer) {
        if self.enabled {
            printer.with_selection(
                printer.focused,
                |printer| self.draw_internal(printer),
            );
        } else {
            printer.with_color(
                ColorStyle::Secondary,
                |printer| self.draw_internal(printer),
            );
        }
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match event {
            Event::Key(Key::Enter) | Event::Char(' ') => {
                self.select();
                EventResult::Consumed(None)
            }
            Event::Mouse {
                event: MouseEvent::Release(MouseButton::Left),
                position,
                offset,
            } if position.fits_in_rect(offset, self.req_size()) =>
            {
                self.select();
                EventResult::Consumed(None)
            }
            _ => EventResult::Ignored,
        }
    }
}
<|endoftext|>


<commit_before>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::latest_version;
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::match_version;
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}://{}:{}/{}/{}/{}/",
                                            req.url.scheme(),
                                            req.url.host(),
                                            req.url.port(),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool);

    let version = match match_version(&conn, &crate_name, req_version) {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let target_name: String =
        ctry!(conn.query("SELECT target_name
                          FROM releases
                          INNER JOIN crates ON crates.id = releases.crate_id
                          WHERE crates.name = $1 AND releases.version = $2",
                         &[&crate_name, &version]))
            .get(0)
            .get(0);

    redirect_to_doc(req, &crate_name, &version, &target_name)
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let version = router.find("version");
    let conn = extension!(req, Pool);
    let version = try!(match_version(&conn, &name, version)
        .ok_or(IronError::new(Nope::ResourceNotFound, status::NotFound)));
    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with("/") {
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
    let latest_version = latest_version(&crate_details.versions, &version);

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", latest_version.is_none())
        .set("latest_version", &latest_version.unwrap_or(String::new()))
        .to_resp("rustdoc")
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool);

    let options = match match_version(&conn, &name, Some(&version)) {
        Some(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool);

            if let Some(file) = File::from_path(conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<commit_msg>redirect from docs.rs/crate-name to crate details if docs failed<commit_after>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::latest_version;
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::match_version;
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}://{}:{}/{}/{}/{}/",
                                            req.url.scheme(),
                                            req.url.host(),
                                            req.url.port(),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}://{}:{}/crate/{}/{}",
                                            req.url.scheme(),
                                            req.url.host(),
                                            req.url.port(),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool);

    let version = match match_version(&conn, &crate_name, req_version) {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let version = router.find("version");
    let conn = extension!(req, Pool);
    let version = try!(match_version(&conn, &name, version)
        .ok_or(IronError::new(Nope::ResourceNotFound, status::NotFound)));
    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with("/") {
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
    let latest_version = latest_version(&crate_details.versions, &version);

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", latest_version.is_none())
        .set("latest_version", &latest_version.unwrap_or(String::new()))
        .to_resp("rustdoc")
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool);

    let options = match match_version(&conn, &name, Some(&version)) {
        Some(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool);

            if let Some(file) = File::from_path(conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<|endoftext|>