<commit_before>use image;
use image::GenericImage;
use image::ImageBuffer;
use image::FilterType;
use image::imageops::resize;
use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::fs::DirBuilder;
use std::hash::{Hash, Hasher};
use std::path::*;

use errors::*;
use utils;

const THUMBNAILS_PATH: &'static str = "thumbnails";

fn hash(path: &Path, dimension: u32) -> u64 {
	let path_string = path.to_string_lossy();
	let hash_input = format!("{}:{}", path_string, dimension.to_string());
	let mut hasher = DefaultHasher::new();
	hash_input.hash(&mut hasher);
	hasher.finish()
}

pub fn get_thumbnail(real_path: &Path, max_dimension: u32) -> Result<PathBuf> {

	let mut out_path = utils::get_data_root()?;
	out_path.push(THUMBNAILS_PATH);

	let mut dir_builder = DirBuilder::new();
	dir_builder.recursive(true);
	dir_builder.create(out_path.as_path())?;

	let source_image = image::open(real_path)?;
	let (source_width, source_height) = source_image.dimensions();
	let cropped_dimension = cmp::max(source_width, source_height);
	let out_dimension = cmp::min(max_dimension, cropped_dimension);

	let hash = hash(real_path, out_dimension);
	out_path.push(format!("{}.png", hash.to_string()));

	if !out_path.exists() {
		let source_aspect_ratio: f32 = source_width as f32 / source_height as f32;
		if source_aspect_ratio < 0.8 || source_aspect_ratio > 1.2 {
			let mut cropped_image = ImageBuffer::new(cropped_dimension, cropped_dimension);
			cropped_image.copy_from(&source_image,
			                        (cropped_dimension - source_width) / 2,
			                        (cropped_dimension - source_height) / 2);
			let out_image = resize(&cropped_image,
			                       out_dimension,
			                       out_dimension,
			                       FilterType::Lanczos3);
			out_image.save(out_path.as_path())?;
		} else {
			let out_image = resize(&source_image,
			                       out_dimension,
			                       out_dimension,
			                       FilterType::Lanczos3);
			out_image.save(out_path.as_path())?;
		}
	}

	Ok(out_path)
}
<commit_msg>Improved performance of thumbnail generation<commit_after>use image;
use image::GenericImage;
use image::ImageBuffer;
use image::ImageFormat;
use image::FilterType;
use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::fs::{DirBuilder, File};
use std::hash::{Hash, Hasher};
use std::path::*;

use errors::*;
use utils;

const THUMBNAILS_PATH: &'static str = "thumbnails";

fn hash(path: &Path, dimension: u32) -> u64 {
	let path_string = path.to_string_lossy();
	let hash_input = format!("{}:{}", path_string, dimension.to_string());
	let mut hasher = DefaultHasher::new();
	hash_input.hash(&mut hasher);
	hasher.finish()
}

pub fn get_thumbnail(real_path: &Path, max_dimension: u32) -> Result<PathBuf> {

	let mut out_path = utils::get_data_root()?;
	out_path.push(THUMBNAILS_PATH);

	let mut dir_builder = DirBuilder::new();
	dir_builder.recursive(true);
	dir_builder.create(out_path.as_path())?;

	let source_image = image::open(real_path)?;
	let (source_width, source_height) = source_image.dimensions();
	let cropped_dimension = cmp::max(source_width, source_height);
	let out_dimension = cmp::min(max_dimension, cropped_dimension);

	let hash = hash(real_path, out_dimension);
	out_path.push(format!("{}.png", hash.to_string()));

	if !out_path.exists() {
		let source_aspect_ratio: f32 = source_width as f32 / source_height as f32;
		if source_aspect_ratio < 0.8 || source_aspect_ratio > 1.2 {
			let scaled_image =
				source_image.resize(out_dimension, out_dimension, FilterType::Lanczos3);
			let (scaled_width, scaled_height) = scaled_image.dimensions();
			let mut final_image = ImageBuffer::new(out_dimension, out_dimension);
			final_image.copy_from(&scaled_image,
			                      (out_dimension - scaled_width) / 2,
			                      (out_dimension - scaled_height) / 2);
			final_image.save(&out_path)?;
		} else {
			let mut out_file = File::create(&out_path)?;
			let final_image =
				source_image.resize_exact(max_dimension, out_dimension, FilterType::Lanczos3);
			final_image.save(&mut out_file, ImageFormat::PNG)?;
		};
	}

	Ok(out_path)
}
<|endoftext|>


<commit_before>fn function() {
    println!("called `function()`");
}

// A module named `my`
mod my {
    // A module can contain items like functions
    #[allow(dead_code)]
    fn function() {
        println!("called `my::function()`");
    }

    // Modules can be nested
    mod nested {
        #[allow(dead_code)]
        fn function() {
            println!("called `my::nested::function()`");
        }
    }
}

fn main() {
    function();

    // Items inside a module can be called using their full  path
    // The `println` function lives in the `stdio` module
    // The `stdio` module lives in the `io` module
    // And the `io` module lives in the `std` crate
    std::io::stdio::println("Hello World!");

    // Error! The `my` module is private
    my::function();
    // TODO ^ Comment out this line
}
<commit_msg>mod: fix error message<commit_after>fn function() {
    println!("called `function()`");
}

// A module named `my`
mod my {
    // A module can contain items like functions
    #[allow(dead_code)]
    fn function() {
        println!("called `my::function()`");
    }

    // Modules can be nested
    mod nested {
        #[allow(dead_code)]
        fn function() {
            println!("called `my::nested::function()`");
        }
    }
}

fn main() {
    function();

    // Items inside a module can be called using their full  path
    // The `println` function lives in the `stdio` module
    // The `stdio` module lives in the `io` module
    // And the `io` module lives in the `std` crate
    std::io::stdio::println("Hello World!");

    // Error! `my::function` is private
    my::function();
    // TODO ^ Comment out this line
}
<|endoftext|>


<commit_before>//! A simple example which prints out information about available Metal devices

extern crate mtl;

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
fn main() {
    println!("Metal is not supported on this platform");
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
fn main() {
    use mtl::ReadOnlyDevice;
    let device = match mtl::Device::system_default_device() {
        Ok(device) => device,
        Err(e) => {
            use std::error::Error;
            println!("{}", e.description());
            return;
        }
    };

    println!("Device:\t\t\t\t\t\t{}", device.get_name());
    println!("Supports 24 bit stencil and 8 bit depth:\t{}", device.is_depth24_stencil8_pixel_format_supported());
    println!("Is low power:\t\t\t\t\t{}", device.is_low_power());
    println!("Is headless:\t\t\t\t\t{}", device.is_headless());
}
<commit_msg>Print out the max threads per group in mtlinfo<commit_after>//! A simple example which prints out information about available Metal devices

extern crate mtl;

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
fn main() {
    println!("Metal is not supported on this platform");
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
fn main() {
    use mtl::ReadOnlyDevice;
    let device = match mtl::Device::system_default_device() {
        Ok(device) => device,
        Err(e) => {
            use std::error::Error;
            println!("{}", e.description());
            return;
        }
    };

    println!("Device:\t\t\t\t\t\t{}", device.get_name());
    println!("Supports 24 bit stencil and 8 bit depth:\t{}", device.is_depth24_stencil8_pixel_format_supported());
    {
        let max_tpg = device.max_threads_per_group();
        println!("Maximum threads per group:\t\t\t({}, {}, {})", max_tpg.width, max_tpg.height, max_tpg.depth);
    }
    println!("Is low power:\t\t\t\t\t{}", device.is_low_power());
    println!("Is headless:\t\t\t\t\t{}", device.is_headless());
}
<|endoftext|>


<commit_before>
use ndarray::{Ix2, Array, NdFloat, ArrayBase, DataMut};

use matrix::{Matrix, MFloat};
use square::SquareMatrix;
use error::LinalgError;
use solve::ImplSolve;

pub trait TriangularMatrix: Matrix + SquareMatrix {
    /// solve a triangular system with upper triangular matrix
    fn solve_upper(&self, Self::Vector) -> Result<Self::Vector, LinalgError>;
    /// solve a triangular system with lower triangular matrix
    fn solve_lower(&self, Self::Vector) -> Result<Self::Vector, LinalgError>;
}

impl<A: MFloat> TriangularMatrix for Array<A, Ix2> {
    fn solve_upper(&self, b: Self::Vector) -> Result<Self::Vector, LinalgError> {
        self.check_square()?;
        let (n, _) = self.size();
        let layout = self.layout()?;
        let a = self.as_slice_memory_order().unwrap();
        let x = ImplSolve::solve_triangle(layout, 'U' as u8, n, a, b.into_raw_vec())?;
        Ok(Array::from_vec(x))
    }
    fn solve_lower(&self, b: Self::Vector) -> Result<Self::Vector, LinalgError> {
        self.check_square()?;
        let (n, _) = self.size();
        let layout = self.layout()?;
        let a = self.as_slice_memory_order().unwrap();
        let x = ImplSolve::solve_triangle(layout, 'L' as u8, n, a, b.into_raw_vec())?;
        Ok(Array::from_vec(x))
    }
}

pub fn drop_upper<A: NdFloat, S>(mut a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix2>
    where S: DataMut<Elem = A>
{
    for ((i, j), val) in a.indexed_iter_mut() {
        if i < j {
            *val = A::zero();
        }
    }
    a
}

pub fn drop_lower<A: NdFloat, S>(mut a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix2>
    where S: DataMut<Elem = A>
{
    for ((i, j), val) in a.indexed_iter_mut() {
        if i > j {
            *val = A::zero();
        }
    }
    a
}
<commit_msg>Implement TriangularMatrix for RcArray<commit_after>
use ndarray::{Ix2, Array, RcArray, NdFloat, ArrayBase, DataMut};

use matrix::{Matrix, MFloat};
use square::SquareMatrix;
use error::LinalgError;
use solve::ImplSolve;

pub trait TriangularMatrix: Matrix + SquareMatrix {
    /// solve a triangular system with upper triangular matrix
    fn solve_upper(&self, Self::Vector) -> Result<Self::Vector, LinalgError>;
    /// solve a triangular system with lower triangular matrix
    fn solve_lower(&self, Self::Vector) -> Result<Self::Vector, LinalgError>;
}

impl<A: MFloat> TriangularMatrix for Array<A, Ix2> {
    fn solve_upper(&self, b: Self::Vector) -> Result<Self::Vector, LinalgError> {
        self.check_square()?;
        let (n, _) = self.size();
        let layout = self.layout()?;
        let a = self.as_slice_memory_order().unwrap();
        let x = ImplSolve::solve_triangle(layout, 'U' as u8, n, a, b.into_raw_vec())?;
        Ok(Array::from_vec(x))
    }
    fn solve_lower(&self, b: Self::Vector) -> Result<Self::Vector, LinalgError> {
        self.check_square()?;
        let (n, _) = self.size();
        let layout = self.layout()?;
        let a = self.as_slice_memory_order().unwrap();
        let x = ImplSolve::solve_triangle(layout, 'L' as u8, n, a, b.into_raw_vec())?;
        Ok(Array::from_vec(x))
    }
}

impl<A: MFloat> TriangularMatrix for RcArray<A, Ix2> {
    fn solve_upper(&self, b: Self::Vector) -> Result<Self::Vector, LinalgError> {
        let x = self.to_owned().solve_upper(b.to_owned())?;
        Ok(x.into_shared())
    }
    fn solve_lower(&self, b: Self::Vector) -> Result<Self::Vector, LinalgError> {
        let x = self.to_owned().solve_lower(b.to_owned())?;
        Ok(x.into_shared())
    }
}

pub fn drop_upper<A: NdFloat, S>(mut a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix2>
    where S: DataMut<Elem = A>
{
    for ((i, j), val) in a.indexed_iter_mut() {
        if i < j {
            *val = A::zero();
        }
    }
    a
}

pub fn drop_lower<A: NdFloat, S>(mut a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix2>
    where S: DataMut<Elem = A>
{
    for ((i, j), val) in a.indexed_iter_mut() {
        if i > j {
            *val = A::zero();
        }
    }
    a
}
<|endoftext|>


<commit_before>use nom::{
  be_u8, be_u16,
  IResult,
  ErrorCode, Err,
};

use frame::{
  ChannelAssignment, NumberType,
  Frame,
  Header, Footer,
};

use metadata::StreamInfo;
use utility::{crc8, crc16, to_u32};

pub fn frame_parser<'a>(input: &'a [u8], stream_info: &StreamInfo)
                        -> IResult<'a, &'a [u8], Frame> {
  let result = chain!(input,
    frame_header: apply!(header, stream_info) ~
    frame_footer: footer,
    || {
      Frame {
        header: frame_header,
        footer: frame_footer,
      }
    }
  );

  match result {
    IResult::Done(i, frame)   => {
      // All frame bytes before the crc-16
      let end         = (input.len() - i.len()) - 2;
      let Footer(crc) = frame.footer;

      if crc16(&input[0..end]) == crc {
        IResult::Done(i, frame)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

pub fn blocking_strategy(input: &[u8]) -> IResult<&[u8], bool> {
  match take!(input, 2) {
    IResult::Done(i, bytes)   => {
      let sync_code = ((bytes[0] as u16) << 6) +
                      ((bytes[1] as u16) >> 2);
      let is_valid  = ((bytes[1] >> 1) & 0b01) == 0;

      if sync_code == 0b11111111111110 && is_valid {
        let is_variable_block_size = (bytes[1] & 0b01) == 1;

        IResult::Done(i, is_variable_block_size)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

pub fn block_sample(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
  match be_u8(input) {
    IResult::Done(i, byte)    => {
      let block_byte  = byte >> 4;
      let sample_byte = byte & 0x0f;
      let is_valid    = block_byte != 0b0000 && sample_byte != 0b1111;

      if is_valid {
        IResult::Done(i, (block_byte, sample_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn channel_bits(input: &[u8]) -> IResult<&[u8], (ChannelAssignment, u8, u8)> {
  match be_u8(input) {
    IResult::Done(i, byte)    => {
      let mut channels       = 2;
      let channel_byte       = byte >> 4;
      let channel_assignment = match channel_byte {
        0b0000...0b0111 => {
          channels = channel_byte + 1;

          ChannelAssignment::Independent
        }
        0b1000          => ChannelAssignment::LeftSide,
        0b1001          => ChannelAssignment::RightSide,
        0b1010          => ChannelAssignment::MiddleSide,
        _               => ChannelAssignment::Independent,
      };
      let size_byte = (byte >> 1) & 0b0111;

      // Checks the validity of:
      //
      // * (4 bits) channel assignment
      // * (3 bits) sample size
      // * (1 bit) last bit
      //
      // All these checks are whether of not they are reserved and should
      // return an error if so.
      let is_valid = channel_byte < 0b1011 &&
                     (size_byte != 0b0011 && size_byte != 0b0111) &&
                     (byte & 0b01) == 0;

      if is_valid {
        IResult::Done(i, (channel_assignment, channels, size_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn utf8_size(input: &[u8], is_u64: bool)
             -> IResult<&[u8], Option<(usize, u8)>> {
  map!(input, be_u8, |utf8_header| {
    match utf8_header {
      0b00000000...0b01111111 => Some((0, utf8_header)),
      0b11000000...0b11011111 => Some((1, utf8_header & 0b00011111)),
      0b11100000...0b11101111 => Some((2, utf8_header & 0b00001111)),
      0b11110000...0b11110111 => Some((3, utf8_header & 0b00000111)),
      0b11111000...0b11111011 => Some((4, utf8_header & 0b00000011)),
      0b11111100...0b11111101 => Some((5, utf8_header & 0b00000001)),
      0b11111110              => if is_u64 { Some((6, 0)) } else { None },
      _                       => None,
    }
  })
}

fn number_type(input: &[u8], is_sample: bool,
               (size, value): (usize, u8))
               -> IResult<&[u8], NumberType> {
  let mut result   = value as u64;
  let mut is_error = false;

  match take!(input, size) {
    IResult::Done(i, bytes)   => {
      for i in 0..size {
        let byte = bytes[i] as u64;

        if byte >= 0b10000000 && byte <= 0b10111111 {
          result = (result << 6) + (byte & 0b00111111);
        } else {
          is_error = true;
          break;
        }
      }

      if is_error {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      } else if is_sample {
        IResult::Done(i, NumberType::Sample(result))
      } else {
        IResult::Done(i, NumberType::Frame(result as u32))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn secondary_block_size(input: &[u8], block_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match block_byte {
    0b0110 => opt!(input, map!(take!(1), to_u32)),
    0b0111 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn secondary_sample_rate(input: &[u8], sample_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match sample_byte {
    0b1100          => opt!(input, map!(take!(1), to_u32)),
    0b1101 | 0b1110 => opt!(input, map!(take!(2), to_u32)),
    _               => IResult::Done(input, None)
  }
}

pub fn header<'a>(input: &'a [u8], stream_info: &StreamInfo)
                  -> IResult<'a, &'a [u8], Header> {
  let result = chain!(input,
    is_variable_block_size: blocking_strategy ~
    tuple0: block_sample ~
    tuple1: channel_bits ~
    number_opt: apply!(utf8_size, is_variable_block_size) ~
    number_length: expr_opt!(number_opt) ~
    number: apply!(number_type, is_variable_block_size, number_length) ~
    alt_block_size: apply!(secondary_block_size, tuple0.0) ~
    alt_sample_rate: apply!(secondary_sample_rate, tuple0.1) ~
    crc: be_u8,
    || {
      let (block_byte, sample_byte)                 = tuple0;
      let (channel_assignment, channels, size_byte) = tuple1;

      let block_size = match block_byte {
        0b0001          => 192,
        0b0010...0b0101 => 576 * 2_u32.pow(block_byte as u32 - 2),
        0b0110 | 0b0111 => alt_block_size.unwrap() + 1,
        0b1000...0b1111 => 256 * 2_u32.pow(block_byte as u32 - 8),
        _               => unreachable!(),
      };

      let sample_rate = match sample_byte {
        0b0000 => stream_info.sample_rate,
        0b0001 => 88200,
        0b0010 => 176400,
        0b0011 => 192000,
        0b0100 => 8000,
        0b0101 => 16000,
        0b0110 => 22050,
        0b0111 => 24000,
        0b1000 => 32000,
        0b1001 => 44100,
        0b1010 => 48000,
        0b1011 => 96000,
        0b1100 => alt_sample_rate.unwrap() * 1000,
        0b1101 => alt_sample_rate.unwrap(),
        0b1110 => alt_sample_rate.unwrap() * 10,
        _      => unreachable!(),
      };

      let bits_per_sample = match size_byte {
        0b0000 => stream_info.bits_per_sample as usize,
        0b0001 => 8,
        0b0010 => 12,
        0b0100 => 16,
        0b0101 => 20,
        0b0110 => 24,
        _      => unreachable!(),
      };

      Header {
        block_size: block_size,
        sample_rate: sample_rate,
        channels: channels,
        channel_assignment: channel_assignment,
        bits_per_sample: bits_per_sample,
        number: number,
        crc: crc,
      }
    }
  );

  match result {
    IResult::Done(i, frame_header) => {
      // All header bytes before the crc-8
      let end = (input.len() - i.len()) - 1;

      if crc8(&input[0..end]) == frame_header.crc {
        IResult::Done(i, frame_header)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)          => IResult::Error(error),
    IResult::Incomplete(need)      => IResult::Incomplete(need),
  }
}

named!(pub footer <&[u8], Footer>, map!(be_u16, Footer));

#[cfg(test)]
mod tests {
  use super::*;
  use frame::{
    Header, Footer,
    ChannelAssignment, NumberType,
  };
  use metadata::StreamInfo;
  use nom::{IResult, Err, ErrorCode};

  #[test]
  fn test_blocking_strategy() {
    let inputs = [b"\xff\xf8", b"\xff\xf9", b"\xfe\xf8", b"\xff\xfa"];
    let slice  = &[][..];
    let error  = |input|
      IResult::Error(Err::Position(ErrorCode::Digit as u32, input));

    assert_eq!(blocking_strategy(inputs[0]), IResult::Done(slice, false));
    assert_eq!(blocking_strategy(inputs[1]), IResult::Done(slice, true));
    assert_eq!(blocking_strategy(inputs[2]), error(inputs[2]));
    assert_eq!(blocking_strategy(inputs[3]), error(inputs[3]));
  }

  #[test]
  fn test_header() {
    let inputs   = [ &b"\xff\xf8\x53\x1c\xf0\x90\x80\x80\x2e"[..]
                   , &b"\xff\xf9\x7c\xa0\xfe\xbf\xbf\xbf\xbf\xbf\xbc\x01\xff\
                        \x01\x88"[..]
                   , &b"\xff\xf8\xc8\x72\x40\x19"[..]
                   ];
    let mut info = StreamInfo::new();
    let results  = [ IResult::Done(&[][..], Header {
                      block_size: 4608,
                      sample_rate: 192000,
                      channels: 2,
                      channel_assignment: ChannelAssignment::Independent,
                      bits_per_sample: 24,
                      number: NumberType::Frame(65536),
                      crc: 0x2e,
                    })
                  , IResult::Done(&[][..], Header {
                      block_size: 512,
                      sample_rate: 1000,
                      channels: 2,
                      channel_assignment: ChannelAssignment::MiddleSide,
                      bits_per_sample: 16,
                      number: NumberType::Sample(68719476732),
                      crc: 0x88,
                    })
                  , IResult::Done(&[][..], Header {
                      block_size: 4096,
                      sample_rate: 32000,
                      channels: 8,
                      channel_assignment: ChannelAssignment::Independent,
                      bits_per_sample: 8,
                      number: NumberType::Frame(64),
                      crc: 0x19,
                    })
                  ];

    info.bits_per_sample = 16;

    assert_eq!(header(inputs[0], &info), results[0]);
    assert_eq!(header(inputs[1], &info), results[1]);
    assert_eq!(header(inputs[2], &info), results[2]);
  }

  #[test]
  fn test_footer() {
    let input  = b"\x03\xe8";
    let result = IResult::Done(&[][..], Footer(0x03e8));

    assert_eq!(footer(input), result);
  }
}
<commit_msg>Add non-error tests for block_sample<commit_after>use nom::{
  be_u8, be_u16,
  IResult,
  ErrorCode, Err,
};

use frame::{
  ChannelAssignment, NumberType,
  Frame,
  Header, Footer,
};

use metadata::StreamInfo;
use utility::{crc8, crc16, to_u32};

pub fn frame_parser<'a>(input: &'a [u8], stream_info: &StreamInfo)
                        -> IResult<'a, &'a [u8], Frame> {
  let result = chain!(input,
    frame_header: apply!(header, stream_info) ~
    frame_footer: footer,
    || {
      Frame {
        header: frame_header,
        footer: frame_footer,
      }
    }
  );

  match result {
    IResult::Done(i, frame)   => {
      // All frame bytes before the crc-16
      let end         = (input.len() - i.len()) - 2;
      let Footer(crc) = frame.footer;

      if crc16(&input[0..end]) == crc {
        IResult::Done(i, frame)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

pub fn blocking_strategy(input: &[u8]) -> IResult<&[u8], bool> {
  match take!(input, 2) {
    IResult::Done(i, bytes)   => {
      let sync_code = ((bytes[0] as u16) << 6) +
                      ((bytes[1] as u16) >> 2);
      let is_valid  = ((bytes[1] >> 1) & 0b01) == 0;

      if sync_code == 0b11111111111110 && is_valid {
        let is_variable_block_size = (bytes[1] & 0b01) == 1;

        IResult::Done(i, is_variable_block_size)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

pub fn block_sample(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
  match be_u8(input) {
    IResult::Done(i, byte)    => {
      let block_byte  = byte >> 4;
      let sample_byte = byte & 0x0f;
      let is_valid    = block_byte != 0b0000 && sample_byte != 0b1111;

      if is_valid {
        IResult::Done(i, (block_byte, sample_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn channel_bits(input: &[u8]) -> IResult<&[u8], (ChannelAssignment, u8, u8)> {
  match be_u8(input) {
    IResult::Done(i, byte)    => {
      let mut channels       = 2;
      let channel_byte       = byte >> 4;
      let channel_assignment = match channel_byte {
        0b0000...0b0111 => {
          channels = channel_byte + 1;

          ChannelAssignment::Independent
        }
        0b1000          => ChannelAssignment::LeftSide,
        0b1001          => ChannelAssignment::RightSide,
        0b1010          => ChannelAssignment::MiddleSide,
        _               => ChannelAssignment::Independent,
      };
      let size_byte = (byte >> 1) & 0b0111;

      // Checks the validity of:
      //
      // * (4 bits) channel assignment
      // * (3 bits) sample size
      // * (1 bit) last bit
      //
      // All these checks are whether of not they are reserved and should
      // return an error if so.
      let is_valid = channel_byte < 0b1011 &&
                     (size_byte != 0b0011 && size_byte != 0b0111) &&
                     (byte & 0b01) == 0;

      if is_valid {
        IResult::Done(i, (channel_assignment, channels, size_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn utf8_size(input: &[u8], is_u64: bool)
             -> IResult<&[u8], Option<(usize, u8)>> {
  map!(input, be_u8, |utf8_header| {
    match utf8_header {
      0b00000000...0b01111111 => Some((0, utf8_header)),
      0b11000000...0b11011111 => Some((1, utf8_header & 0b00011111)),
      0b11100000...0b11101111 => Some((2, utf8_header & 0b00001111)),
      0b11110000...0b11110111 => Some((3, utf8_header & 0b00000111)),
      0b11111000...0b11111011 => Some((4, utf8_header & 0b00000011)),
      0b11111100...0b11111101 => Some((5, utf8_header & 0b00000001)),
      0b11111110              => if is_u64 { Some((6, 0)) } else { None },
      _                       => None,
    }
  })
}

fn number_type(input: &[u8], is_sample: bool,
               (size, value): (usize, u8))
               -> IResult<&[u8], NumberType> {
  let mut result   = value as u64;
  let mut is_error = false;

  match take!(input, size) {
    IResult::Done(i, bytes)   => {
      for i in 0..size {
        let byte = bytes[i] as u64;

        if byte >= 0b10000000 && byte <= 0b10111111 {
          result = (result << 6) + (byte & 0b00111111);
        } else {
          is_error = true;
          break;
        }
      }

      if is_error {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      } else if is_sample {
        IResult::Done(i, NumberType::Sample(result))
      } else {
        IResult::Done(i, NumberType::Frame(result as u32))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn secondary_block_size(input: &[u8], block_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match block_byte {
    0b0110 => opt!(input, map!(take!(1), to_u32)),
    0b0111 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn secondary_sample_rate(input: &[u8], sample_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match sample_byte {
    0b1100          => opt!(input, map!(take!(1), to_u32)),
    0b1101 | 0b1110 => opt!(input, map!(take!(2), to_u32)),
    _               => IResult::Done(input, None)
  }
}

pub fn header<'a>(input: &'a [u8], stream_info: &StreamInfo)
                  -> IResult<'a, &'a [u8], Header> {
  let result = chain!(input,
    is_variable_block_size: blocking_strategy ~
    tuple0: block_sample ~
    tuple1: channel_bits ~
    number_opt: apply!(utf8_size, is_variable_block_size) ~
    number_length: expr_opt!(number_opt) ~
    number: apply!(number_type, is_variable_block_size, number_length) ~
    alt_block_size: apply!(secondary_block_size, tuple0.0) ~
    alt_sample_rate: apply!(secondary_sample_rate, tuple0.1) ~
    crc: be_u8,
    || {
      let (block_byte, sample_byte)                 = tuple0;
      let (channel_assignment, channels, size_byte) = tuple1;

      let block_size = match block_byte {
        0b0001          => 192,
        0b0010...0b0101 => 576 * 2_u32.pow(block_byte as u32 - 2),
        0b0110 | 0b0111 => alt_block_size.unwrap() + 1,
        0b1000...0b1111 => 256 * 2_u32.pow(block_byte as u32 - 8),
        _               => unreachable!(),
      };

      let sample_rate = match sample_byte {
        0b0000 => stream_info.sample_rate,
        0b0001 => 88200,
        0b0010 => 176400,
        0b0011 => 192000,
        0b0100 => 8000,
        0b0101 => 16000,
        0b0110 => 22050,
        0b0111 => 24000,
        0b1000 => 32000,
        0b1001 => 44100,
        0b1010 => 48000,
        0b1011 => 96000,
        0b1100 => alt_sample_rate.unwrap() * 1000,
        0b1101 => alt_sample_rate.unwrap(),
        0b1110 => alt_sample_rate.unwrap() * 10,
        _      => unreachable!(),
      };

      let bits_per_sample = match size_byte {
        0b0000 => stream_info.bits_per_sample as usize,
        0b0001 => 8,
        0b0010 => 12,
        0b0100 => 16,
        0b0101 => 20,
        0b0110 => 24,
        _      => unreachable!(),
      };

      Header {
        block_size: block_size,
        sample_rate: sample_rate,
        channels: channels,
        channel_assignment: channel_assignment,
        bits_per_sample: bits_per_sample,
        number: number,
        crc: crc,
      }
    }
  );

  match result {
    IResult::Done(i, frame_header) => {
      // All header bytes before the crc-8
      let end = (input.len() - i.len()) - 1;

      if crc8(&input[0..end]) == frame_header.crc {
        IResult::Done(i, frame_header)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)          => IResult::Error(error),
    IResult::Incomplete(need)      => IResult::Incomplete(need),
  }
}

named!(pub footer <&[u8], Footer>, map!(be_u16, Footer));

#[cfg(test)]
mod tests {
  use super::*;
  use frame::{
    Header, Footer,
    ChannelAssignment, NumberType,
  };
  use metadata::StreamInfo;
  use nom::{IResult, Err, ErrorCode};

  #[test]
  fn test_blocking_strategy() {
    let inputs = [b"\xff\xf8", b"\xff\xf9", b"\xfe\xf8", b"\xff\xfa"];
    let slice  = &[][..];
    let error  = |input|
      IResult::Error(Err::Position(ErrorCode::Digit as u32, input));

    assert_eq!(blocking_strategy(inputs[0]), IResult::Done(slice, false));
    assert_eq!(blocking_strategy(inputs[1]), IResult::Done(slice, true));
    assert_eq!(blocking_strategy(inputs[2]), error(inputs[2]));
    assert_eq!(blocking_strategy(inputs[3]), error(inputs[3]));
  }

  #[test]
  fn test_block_sample() {
    let inputs = [b"\xf9", b"\x1a"];
    let slice  = &[][..];

    assert_eq!(block_sample(inputs[0]), IResult::Done(slice, (0x0f, 0x09)));
    assert_eq!(block_sample(inputs[1]), IResult::Done(slice, (0x01, 0x0a)));
  }

  #[test]
  fn test_header() {
    let inputs   = [ &b"\xff\xf8\x53\x1c\xf0\x90\x80\x80\x2e"[..]
                   , &b"\xff\xf9\x7c\xa0\xfe\xbf\xbf\xbf\xbf\xbf\xbc\x01\xff\
                        \x01\x88"[..]
                   , &b"\xff\xf8\xc8\x72\x40\x19"[..]
                   ];
    let mut info = StreamInfo::new();
    let results  = [ IResult::Done(&[][..], Header {
                      block_size: 4608,
                      sample_rate: 192000,
                      channels: 2,
                      channel_assignment: ChannelAssignment::Independent,
                      bits_per_sample: 24,
                      number: NumberType::Frame(65536),
                      crc: 0x2e,
                    })
                  , IResult::Done(&[][..], Header {
                      block_size: 512,
                      sample_rate: 1000,
                      channels: 2,
                      channel_assignment: ChannelAssignment::MiddleSide,
                      bits_per_sample: 16,
                      number: NumberType::Sample(68719476732),
                      crc: 0x88,
                    })
                  , IResult::Done(&[][..], Header {
                      block_size: 4096,
                      sample_rate: 32000,
                      channels: 8,
                      channel_assignment: ChannelAssignment::Independent,
                      bits_per_sample: 8,
                      number: NumberType::Frame(64),
                      crc: 0x19,
                    })
                  ];

    info.bits_per_sample = 16;

    assert_eq!(header(inputs[0], &info), results[0]);
    assert_eq!(header(inputs[1], &info), results[1]);
    assert_eq!(header(inputs[2], &info), results[2]);
  }

  #[test]
  fn test_footer() {
    let input  = b"\x03\xe8";
    let result = IResult::Done(&[][..], Footer(0x03e8));

    assert_eq!(footer(input), result);
  }
}
<|endoftext|>


<commit_before>use std::sync::{Barrier, RwLock, Arc, RwLockWriteGuard};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::Ordering as AtOrd;
extern crate rand;
use rand::{ThreadRng, Rng};
use rand::distributions::{IndependentSample, Range};

extern crate gr;
use gr::{GI, width_box, split_box, midpoint_box, eps_tol};

extern crate gelpia_utils;
use gelpia_utils::{Quple, INF, NINF, Flt, Parameters};

extern crate function;
use function::FuncObj;

#[derive(Clone)]
pub struct Individual {
    pub solution: Vec<GI>,
    pub fitness: Flt,
}

pub fn ea(x_e: Vec<GI>,
          param: Parameters,
          population: Arc<RwLock<Vec<Individual>>>,
          f_bestag: Arc<RwLock<Flt>>,
          x_bestbb: Arc<RwLock<Vec<GI>>>,
          b1: Arc<Barrier>,
          b2: Arc<Barrier>,
          stop: Arc<AtomicBool>,
          sync: Arc<AtomicBool>,
          fo_c: FuncObj) -> (Flt, Vec<GI>, bool) {
    // Constant function
    if x_e.len() == 0 {
        return (0.0, x_e, true);
    }
    let input = ea_core(&x_e, &param, &stop, &sync, &b1, &b2, &f_bestag,
                        &x_bestbb, population, &fo_c);
    let ans = fo_c.call(&input).upper();

    (ans, input, true)
}

fn ea_core(x_e: &Vec<GI>, param: &Parameters, stop: &Arc<AtomicBool>,
           sync: &Arc<AtomicBool>, b1: &Arc<Barrier>, b2: &Arc<Barrier>,
           f_bestag: &Arc<RwLock<Flt>>,
           x_bestbb: &Arc<RwLock<Vec<GI>>>,
           population: Arc<RwLock<Vec<Individual>>>, fo_c: &FuncObj)
           -> (Vec<GI>) {
    let mut rng = rand::thread_rng();
    let dimension = Range::new(0, x_e.len());
    let mut ranges = Vec::new();
    for g in x_e {
        ranges.push(Range::new(g.lower(), g.upper()));
    }

    while !stop.load(AtOrd::Acquire) {
        if sync.load(AtOrd::Acquire) {
            b1.wait();
            b2.wait();
        }
        let ref mut population = *population.write().unwrap();
        sample(param.population, population, fo_c, &ranges, &mut rng);

        population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());

        for iteration in 0..100 {
            population.truncate(param.elitism);

            for _ in 0..param.selection {
                population.push(rand_individual(fo_c, &ranges, &mut rng));
            }

            next_generation(param.population, population, fo_c, param.mutation,
                            param.crossover, &dimension, &ranges, &mut rng);
            population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());

            // Report fittest of the fit.
            {
                let mut fbest = f_bestag.write().unwrap();

                *fbest =
                    if *fbest < population[0].fitness { population[0].fitness }
                else { *fbest };
            }

            // Kill worst of the worst
            let mut ftg = Vec::new();
            {
                let bestbb = x_bestbb.read().unwrap();
                // From The Gods
                for i in 0..bestbb.len() {
                    ftg.push(Range::new(bestbb[i].lower(), bestbb[i].upper()));
                }
            }
            let worst_ind = population.len() - 1;
            population[worst_ind] = rand_individual(fo_c,
                                                    &ftg,
                                                    &mut rng);
            population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());
        }
    }

    let ref population = *population.read().unwrap();
    let result = if !population.is_empty() {
        population[0].solution.clone()
    } else {
        x_e.clone()
    };

    result
}

fn sample(population_size: usize, population: &mut Vec<Individual>,
          fo_c: &FuncObj, ranges: &Vec<Range<f64>>, rng: &mut ThreadRng)
          -> () {
    for _ in 0..population_size-population.len() {
        population.push(rand_individual(fo_c, ranges, rng));
    }

    ()
}

fn rand_individual(fo_c: &FuncObj, ranges: &Vec<Range<f64>>, rng: &mut ThreadRng)
                   -> (Individual) {
    let mut new_sol = Vec::new();
    for r in ranges {
        new_sol.push(GI::new_p(r.ind_sample(rng)));
    }
    let fitness = fo_c.call(&new_sol).lower();

    Individual{solution:new_sol, fitness:fitness}
}

fn next_generation(population_size:usize, population: &mut Vec<Individual>,
                   fo_c: &FuncObj, mut_rate: f64, crossover: f64,
                   dimension: &Range<usize>, ranges: &Vec<Range<f64>>,
                   rng: &mut ThreadRng)
                   -> () {

    let elites = population.clone();

    for _ in 0..population_size-population.len() {
        if rng.gen::<f64>() < crossover {
            population.push(breed(rng.choose(&elites).unwrap(),
                                  rng.choose(&elites).unwrap(),
                                  fo_c,
                                  dimension, rng));
        } else {
            population.push(mutate(rng.choose(&elites).unwrap(), fo_c, mut_rate,
                                   dimension, ranges, rng));
        }
    }

    ()
}

fn mutate(input: &Individual, fo_c: &FuncObj, mut_rate: f64,
          dimension: &Range<usize>, ranges: &Vec<Range<f64>>, rng: &mut ThreadRng)
          -> (Individual) {
    let mut output_sol = Vec::new();

    for (r, &ind) in ranges.iter().zip(input.solution.iter()) {
        output_sol.push(
            if rng.gen::<f64>() < mut_rate {
                ind
            } else {
                GI::new_p(r.ind_sample(rng))
            });
    }

    let fitness = fo_c.call(&output_sol).lower();

    Individual{solution: output_sol, fitness: fitness}
}

fn breed(parent1: &Individual, parent2: &Individual, fo_c: &FuncObj,
         dimension: &Range<usize>, rng: &mut ThreadRng) -> (Individual) {
    let mut child = parent1.clone();
    let crossover_point = dimension.ind_sample(rng);
    child.solution.truncate(crossover_point);
    let mut rest = parent2.clone().solution.split_off(crossover_point);
    child.solution.append(&mut rest);
    child.fitness = fo_c.call(&child.solution).lower();
    child
}
<commit_msg>Made the RNG have a predetermined seed<commit_after>use std::sync::{Barrier, RwLock, Arc, RwLockWriteGuard};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::Ordering as AtOrd;
extern crate rand;
//use rand::{ThreadRng, Rng};
use rand::{Rng, SeedableRng, StdRng};
use rand::distributions::{IndependentSample, Range};

extern crate gr;
use gr::{GI, width_box, split_box, midpoint_box, eps_tol};

extern crate gelpia_utils;
use gelpia_utils::{Quple, INF, NINF, Flt, Parameters};

extern crate function;
use function::FuncObj;

#[derive(Clone)]
pub struct Individual {
    pub solution: Vec<GI>,
    pub fitness: Flt,
}

pub fn ea(x_e: Vec<GI>,
          param: Parameters,
          population: Arc<RwLock<Vec<Individual>>>,
          f_bestag: Arc<RwLock<Flt>>,
          x_bestbb: Arc<RwLock<Vec<GI>>>,
          b1: Arc<Barrier>,
          b2: Arc<Barrier>,
          stop: Arc<AtomicBool>,
          sync: Arc<AtomicBool>,
          fo_c: FuncObj) -> (Flt, Vec<GI>, bool) {
    // Constant function
    if x_e.len() == 0 {
        return (0.0, x_e, true);
    }
    let input = ea_core(&x_e, &param, &stop, &sync, &b1, &b2, &f_bestag,
                        &x_bestbb, population, &fo_c);
    let ans = fo_c.call(&input).upper();

    (ans, input, true)
}

fn ea_core(x_e: &Vec<GI>, param: &Parameters, stop: &Arc<AtomicBool>,
           sync: &Arc<AtomicBool>, b1: &Arc<Barrier>, b2: &Arc<Barrier>,
           f_bestag: &Arc<RwLock<Flt>>,
           x_bestbb: &Arc<RwLock<Vec<GI>>>,
           population: Arc<RwLock<Vec<Individual>>>, fo_c: &FuncObj)
           -> (Vec<GI>) {
    //    let mut rng = rand::thread_rng();
    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);
    let dimension = Range::new(0, x_e.len());
    let mut ranges = Vec::new();
    for g in x_e {
        ranges.push(Range::new(g.lower(), g.upper()));
    }

    while !stop.load(AtOrd::Acquire) {
        if sync.load(AtOrd::Acquire) {
            b1.wait();
            b2.wait();
        }
        let ref mut population = *population.write().unwrap();
        sample(param.population, population, fo_c, &ranges, &mut rng);

        population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());

        for iteration in 0..100 {
            population.truncate(param.elitism);

            for _ in 0..param.selection {
                population.push(rand_individual(fo_c, &ranges, &mut rng));
            }

            next_generation(param.population, population, fo_c, param.mutation,
                            param.crossover, &dimension, &ranges, &mut rng);
            population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());

            // Report fittest of the fit.
            {
                let mut fbest = f_bestag.write().unwrap();

                *fbest =
                    if *fbest < population[0].fitness { population[0].fitness }
                else { *fbest };
            }

            // Kill worst of the worst
            let mut ftg = Vec::new();
            {
                let bestbb = x_bestbb.read().unwrap();
                // From The Gods
                for i in 0..bestbb.len() {
                    ftg.push(Range::new(bestbb[i].lower(), bestbb[i].upper()));
                }
            }
            let worst_ind = population.len() - 1;
            population[worst_ind] = rand_individual(fo_c,
                                                    &ftg,
                                                    &mut rng);
            population.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap());
        }
    }

    let ref population = *population.read().unwrap();
    let result = if !population.is_empty() {
        population[0].solution.clone()
    } else {
        x_e.clone()
    };

    result
}

fn sample(population_size: usize, population: &mut Vec<Individual>,
          fo_c: &FuncObj, ranges: &Vec<Range<f64>>, rng: &mut StdRng)
          -> () {
    for _ in 0..population_size-population.len() {
        population.push(rand_individual(fo_c, ranges, rng));
    }

    ()
}

fn rand_individual(fo_c: &FuncObj, ranges: &Vec<Range<f64>>, rng: &mut StdRng)
                   -> (Individual) {
    let mut new_sol = Vec::new();
    for r in ranges {
        new_sol.push(GI::new_p(r.ind_sample(rng)));
    }
    let fitness = fo_c.call(&new_sol).lower();

    Individual{solution:new_sol, fitness:fitness}
}

fn next_generation(population_size:usize, population: &mut Vec<Individual>,
                   fo_c: &FuncObj, mut_rate: f64, crossover: f64,
                   dimension: &Range<usize>, ranges: &Vec<Range<f64>>,
                   rng: &mut StdRng)
                   -> () {

    let elites = population.clone();

    for _ in 0..population_size-population.len() {
        if rng.gen::<f64>() < crossover {
            population.push(breed(rng.choose(&elites).unwrap(),
                                  rng.choose(&elites).unwrap(),
                                  fo_c,
                                  dimension, rng));
        } else {
            population.push(mutate(rng.choose(&elites).unwrap(), fo_c, mut_rate,
                                   dimension, ranges, rng));
        }
    }

    ()
}

fn mutate(input: &Individual, fo_c: &FuncObj, mut_rate: f64,
          dimension: &Range<usize>, ranges: &Vec<Range<f64>>, rng: &mut StdRng)
          -> (Individual) {
    let mut output_sol = Vec::new();

    for (r, &ind) in ranges.iter().zip(input.solution.iter()) {
        output_sol.push(
            if rng.gen::<f64>() < mut_rate {
                ind
            } else {
                GI::new_p(r.ind_sample(rng))
            });
    }

    let fitness = fo_c.call(&output_sol).lower();

    Individual{solution: output_sol, fitness: fitness}
}

fn breed(parent1: &Individual, parent2: &Individual, fo_c: &FuncObj,
         dimension: &Range<usize>, rng: &mut StdRng) -> (Individual) {
    let mut child = parent1.clone();
    let crossover_point = dimension.ind_sample(rng);
    child.solution.truncate(crossover_point);
    let mut rest = parent2.clone().solution.split_off(crossover_point);
    child.solution.append(&mut rest);
    child.fitness = fo_c.call(&child.solution).lower();
    child
}
<|endoftext|>


<commit_before>use gfx::handle::ShaderResourceView;
use gfx::{texture, Factory, Resources};
use gfx::format::Rgba8;
use cgmath;
use cgmath::{Matrix4, Point3, Vector3, Point2, Rad};
use game::constants::{TILE_WIDTH, RESOLUTION_X, RESOLUTION_Y, VIEW_DISTANCE};
use graphics::orientation::Orientation;
use gfx_app::mouse_controls::MouseInputState;
use image;
use shaders::Projection;
use std::f32::consts::PI;
use std::io::Cursor;

pub mod camera;
pub mod orientation;

#[derive(Debug)]
pub struct DeltaTime(pub f64);

#[derive(Debug, Clone)]
pub struct Dimensions {
  width: u32,
  height: u32,
}

impl Dimensions {
  pub fn new(_window_width: u32, _window_height: u32) -> Dimensions {
    Dimensions {
      width: RESOLUTION_X,
      height: RESOLUTION_Y,
    }
  }

  pub fn get_view_matrix() -> Matrix4<f32> {
    Matrix4::look_at(
      Point3::new(0.0, 0.0, VIEW_DISTANCE),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    )
  }

  pub fn world_to_projection(&self, input: &camera::CameraInputState) -> Projection {
    let view: Matrix4<f32> = Matrix4::look_at(
      Point3::new(0.0, 0.0, input.distance),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );
    let aspect_ratio = self.width as f32 / self.height as f32;
    Projection {
      model: view.into(),
      view: view.into(),
      proj: cgmath::perspective(cgmath::Deg(75.0f32), aspect_ratio, 0.1, 4000.0).into(),
    }
  }
}

fn flip_y_axel(point: Point2<f32>) -> Point2<f32> {
  Point2 {
    x: point.x,
    y: RESOLUTION_Y as f32 - point.y
  }
}

fn direction(start_point: Point2<f32>, end_point: Point2<f32>) -> i32 {

  let theta= cgmath::Angle::atan2(end_point.y - start_point.y, (end_point.x - start_point.x));
  let angle = match theta {
    Rad(i) => i
  };
  let rad_to_deg = 180.0 / PI;
  let anglei = if angle < 0.0 {
    (angle + 2.0 * PI) * rad_to_deg
  } else {
    angle * rad_to_deg
  };
  anglei.floor() as i32
}

pub fn get_orientation(mouse_input: &MouseInputState) -> Orientation {
  if let Some(end_point_gl) = mouse_input.left_click_point {
    let start_point = Point2 {
      x: (RESOLUTION_X / 2) as f32,
      y: (RESOLUTION_Y / 2) as f32
    };
    let angle_in_degrees = direction(start_point, flip_y_axel(end_point_gl));

    match angle_in_degrees {
      345 ... 360 | 0 ... 22 => Orientation::Right,
      23 ... 68 => Orientation::UpRight,
      69 ... 114 => Orientation::Up,
      115 ... 160 => Orientation::UpLeft,
      161 ... 206 => Orientation::Left,
      207 ... 252 => Orientation::DownLeft,
      253 ... 298 => Orientation::Down,
      299 ... 344 => Orientation::DownRight,
      _ => unreachable!("Invalid orientation")
    }
  } else {
    Orientation::Right
  }
}

fn is_within_map_borders(point: Point2<f64>) -> bool {
  point.x > 0.0 && point.x < 63.0 && point.y > 0.0 && point.y < 63.0
}
pub fn can_move(screen_pos: [f32; 2]) -> bool {
  let x_coord = f64::from(screen_pos[0]);
  let y_coord = f64::from(screen_pos[1]);
  let point = Point2 {
    x: (x_coord / TILE_WIDTH + y_coord / TILE_WIDTH).round() + 32.0,
    y: (y_coord / TILE_WIDTH - x_coord / TILE_WIDTH).round() + 31.0
  };
  is_within_map_borders(point)
}

pub fn load_texture<R, F>(factory: &mut F, data: &[u8]) -> Result<ShaderResourceView<R, [f32; 4]>, String> where R: Resources, F: Factory<R> {
  let img = image::load(Cursor::new(data), image::PNG).unwrap().to_rgba();
  let (width, height) = img.dimensions();
  let kind = texture::Kind::D2(width as texture::Size, height as texture::Size, texture::AaMode::Single);
  let (_, view) = factory.create_texture_immutable_u8::<Rgba8>(kind, &[&img]).unwrap();
  Ok(view)
}
<commit_msg>Flip character coordinate offset values<commit_after>use gfx::handle::ShaderResourceView;
use gfx::{texture, Factory, Resources};
use gfx::format::Rgba8;
use cgmath;
use cgmath::{Matrix4, Point3, Vector3, Point2, Rad};
use game::constants::{TILE_WIDTH, RESOLUTION_X, RESOLUTION_Y, VIEW_DISTANCE};
use graphics::orientation::Orientation;
use gfx_app::mouse_controls::MouseInputState;
use image;
use shaders::Projection;
use std::f32::consts::PI;
use std::io::Cursor;

pub mod camera;
pub mod orientation;

#[derive(Debug)]
pub struct DeltaTime(pub f64);

#[derive(Debug, Clone)]
pub struct Dimensions {
  width: u32,
  height: u32,
}

impl Dimensions {
  pub fn new(_window_width: u32, _window_height: u32) -> Dimensions {
    Dimensions {
      width: RESOLUTION_X,
      height: RESOLUTION_Y,
    }
  }

  pub fn get_view_matrix() -> Matrix4<f32> {
    Matrix4::look_at(
      Point3::new(0.0, 0.0, VIEW_DISTANCE),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    )
  }

  pub fn world_to_projection(&self, input: &camera::CameraInputState) -> Projection {
    let view: Matrix4<f32> = Matrix4::look_at(
      Point3::new(0.0, 0.0, input.distance),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );
    let aspect_ratio = self.width as f32 / self.height as f32;
    Projection {
      model: view.into(),
      view: view.into(),
      proj: cgmath::perspective(cgmath::Deg(75.0f32), aspect_ratio, 0.1, 4000.0).into(),
    }
  }
}

fn flip_y_axel(point: Point2<f32>) -> Point2<f32> {
  Point2 {
    x: point.x,
    y: RESOLUTION_Y as f32 - point.y
  }
}

fn direction(start_point: Point2<f32>, end_point: Point2<f32>) -> i32 {

  let theta= cgmath::Angle::atan2(end_point.y - start_point.y, (end_point.x - start_point.x));
  let angle = match theta {
    Rad(i) => i
  };
  let rad_to_deg = 180.0 / PI;
  let anglei = if angle < 0.0 {
    (angle + 2.0 * PI) * rad_to_deg
  } else {
    angle * rad_to_deg
  };
  anglei.floor() as i32
}

pub fn get_orientation(mouse_input: &MouseInputState) -> Orientation {
  if let Some(end_point_gl) = mouse_input.left_click_point {
    let start_point = Point2 {
      x: (RESOLUTION_X / 2) as f32,
      y: (RESOLUTION_Y / 2) as f32
    };
    let angle_in_degrees = direction(start_point, flip_y_axel(end_point_gl));

    match angle_in_degrees {
      345 ... 360 | 0 ... 22 => Orientation::Right,
      23 ... 68 => Orientation::UpRight,
      69 ... 114 => Orientation::Up,
      115 ... 160 => Orientation::UpLeft,
      161 ... 206 => Orientation::Left,
      207 ... 252 => Orientation::DownLeft,
      253 ... 298 => Orientation::Down,
      299 ... 344 => Orientation::DownRight,
      _ => unreachable!("Invalid orientation")
    }
  } else {
    Orientation::Right
  }
}

fn is_within_map_borders(point: Point2<f64>) -> bool {
  point.x > 0.0 && point.x < 63.0 && point.y > 0.0 && point.y < 63.0
}
pub fn can_move(screen_pos: [f32; 2]) -> bool {
  let x_coord = f64::from(screen_pos[0]);
  let y_coord = f64::from(screen_pos[1]);
  let point = Point2 {
    x: (x_coord / TILE_WIDTH + y_coord / TILE_WIDTH).round() + 31.0,
    y: (y_coord / TILE_WIDTH - x_coord / TILE_WIDTH).round() + 32.0
  };
  is_within_map_borders(point)
}

pub fn load_texture<R, F>(factory: &mut F, data: &[u8]) -> Result<ShaderResourceView<R, [f32; 4]>, String> where R: Resources, F: Factory<R> {
  let img = image::load(Cursor::new(data), image::PNG).unwrap().to_rgba();
  let (width, height) = img.dimensions();
  let kind = texture::Kind::D2(width as texture::Size, height as texture::Size, texture::AaMode::Single);
  let (_, view) = factory.create_texture_immutable_u8::<Rgba8>(kind, &[&img]).unwrap();
  Ok(view)
}
<|endoftext|>


<commit_before>use dynasmrt::x64::Assembler;
use dynasmrt::{DynasmApi, DynasmLabelApi};

use super::*;
use peephole;

dynasm!(asm
    ; .alias pointer, r12
    ; .alias mem_start, r13
    ; .alias mem_limit, r14
    ; .alias rts, r15
);

pub fn compile(program: &peephole::Program) -> Program {
    let mut asm = dynasmrt::x64::Assembler::new();
    let start = asm.offset();

    dynasm!(asm
        ; push r12
        ; push r13
        ; push r14
        ; push r15
        ; mov pointer, rcx
        ; mov mem_start, rcx
        ; mov mem_limit, rcx
        ; add mem_limit, rdx
        ; mov rts, r8
    );

    compile_sequence(&mut asm, program);

    dynasm!(asm
        ; mov rax, rts::OKAY as i32
        ; jmp ->finish

        ; ->underflow:
        ; mov rax, rts::UNDERFLOW as i32
        ; jmp ->finish

        ; ->overflow:
        ; mov rax, rts::OVERFLOW as i32

        ; ->finish:
        ; pop r15
        ; pop r14
        ; pop r13
        ; pop r12
        ; ret
    );

    let code = asm.finalize().unwrap();

    Program {
        code: code,
        start: start,
    }
}

pub fn compile_sequence(asm: &mut Assembler, program: &[peephole::Instruction]) {
    for instruction in program {
        compile_instruction(asm, instruction);
    }
}

macro_rules! check_pos_offset {
    ($asm:ident, $offset:expr) => {{
        dynasm!($asm
            ; mov rax, QWORD $offset as i64
        );

        if cfg!(not(feature = "omit_bounds_checks")) {
            dynasm!($asm
                ; mov rcx, mem_limit
                ; sub rcx, pointer
                ; cmp rcx, rax
                ; jle -> overflow
            );
        }
    }}
}

macro_rules! check_neg_offset {
    ($asm:ident, $offset:expr) => {{
        dynasm!($asm
            ; mov rax, QWORD $offset as i64
        );

        if cfg!(not(feature = "omit_bounds_checks")) {
            dynasm!($asm
                ; mov rcx, pointer
                ; sub rcx, mem_start
                ; cmp rcx, rax
                ; jl ->underflow
            );
        }
    }}
}

pub fn compile_instruction(asm: &mut Assembler, instruction: &peephole::Instruction) {
    use peephole::Instruction::*;

    match *instruction {
        Right(count) => {
            dynasm!(asm
                ;; check_pos_offset!(asm, count)
                ; add pointer, rax
            );
        }

        Left(count) => {
            dynasm!(asm
                ;; check_neg_offset!(asm, count)
                ; sub pointer, rax
            );
        }

        Change(count) => {
            dynasm!(asm
                ; add [pointer], BYTE u8_to_i8(count)
            );
        }

        In => {
            dynasm!(asm
                ; mov rax, QWORD rts::RtsState::read as _
                ; mov rcx, rts
                ; sub rsp, BYTE 0x28
                ; call rax
                ; add rsp, BYTE 0x28
                ; mov [pointer], al
            );
        }

        Out => {
            dynasm!(asm
                ; mov rax, QWORD rts::RtsState::write as _
                ; mov rcx, rts
                ; xor rdx, rdx
                ; mov dl, [pointer]
                ; sub rsp, BYTE 0x28
                ; call rax
                ; add rsp, BYTE 0x28
            );
        }

        SetZero => {
            dynasm!(asm
                ; mov BYTE [pointer], 0
            )
        }

        FindZeroRight(skip) => {
            dynasm!(asm
                ; jmp >end_loop
                ; begin_loop:
                ;; check_pos_offset!(asm, skip)
                ; add pointer, rax
                ; end_loop:
                ; cmp BYTE [pointer], 0
                ; jnz <begin_loop
            )
        }

        FindZeroLeft(skip) => {
            dynasm!(asm
                ; jmp >end_loop
                ; begin_loop:
                ;; check_neg_offset!(asm, skip)
                ; sub pointer, rax
                ; end_loop:
                ; cmp BYTE [pointer], 0
                ; jnz <begin_loop
            )
        }

        OffsetAddRight(offset) => {
            dynasm!(asm
                ; cmp BYTE [pointer], 0
                ; jz >skip
                ;; check_pos_offset!(asm, offset)
                ; mov cl, BYTE [pointer]
                ; mov BYTE [pointer], 0
                ; add BYTE [pointer + rax], cl
                ; skip:
            );
        }

        OffsetAddLeft(offset) => {
            dynasm!(asm
                ; cmp BYTE [pointer], 0
                ; jz >skip
                ;; check_neg_offset!(asm, offset)
                ; mov cl, BYTE [pointer]
                ; mov BYTE [pointer], 0
                ; neg rax
                ; add BYTE [pointer + rax], cl
                ; skip:
            );
        }

        Loop(ref body) => {
            let begin_label = asm.new_dynamic_label();
            let end_label   = asm.new_dynamic_label();

            dynasm!(asm
                ; jmp =>end_label
                ; =>begin_label
            );

            compile_sequence(asm, body);

            dynasm!(asm
                ; =>end_label
                ; cmp BYTE [pointer], 0
                ; jnz =>begin_label
            );
        }
    }
}

fn u8_to_i8(n: u8) -> i8 {
    let mut n = n as isize % 256;
    if n > 127 { n -= 256 };
    n as i8
}
<commit_msg>Changed offset-loading macros to functions.<commit_after>use dynasmrt::x64::Assembler;
use dynasmrt::{DynasmApi, DynasmLabelApi};

use super::*;
use peephole;

dynasm!(asm
    ; .alias pointer, r12
    ; .alias mem_start, r13
    ; .alias mem_limit, r14
    ; .alias rts, r15
);

pub fn compile(program: &peephole::Program) -> Program {
    let mut asm = dynasmrt::x64::Assembler::new();
    let start = asm.offset();

    dynasm!(asm
        ; push r12
        ; push r13
        ; push r14
        ; push r15
        ; mov pointer, rcx
        ; mov mem_start, rcx
        ; mov mem_limit, rcx
        ; add mem_limit, rdx
        ; mov rts, r8
    );

    compile_sequence(&mut asm, program);

    dynasm!(asm
        ; mov rax, rts::OKAY as i32
        ; jmp ->finish

        ; ->underflow:
        ; mov rax, rts::UNDERFLOW as i32
        ; jmp ->finish

        ; ->overflow:
        ; mov rax, rts::OVERFLOW as i32

        ; ->finish:
        ; pop r15
        ; pop r14
        ; pop r13
        ; pop r12
        ; ret
    );

    let code = asm.finalize().unwrap();

    Program {
        code: code,
        start: start,
    }
}

pub fn compile_sequence(asm: &mut Assembler, program: &[peephole::Instruction]) {
    for instruction in program {
        compile_instruction(asm, instruction);
    }
}

pub fn compile_instruction(asm: &mut Assembler, instruction: &peephole::Instruction) {
    use peephole::Instruction::*;

    match *instruction {
        Right(count) => {
            dynasm!(asm
                ;; load_pos_offset(asm, count)
                ; add pointer, rax
            );
        }

        Left(count) => {
            dynasm!(asm
                ;; load_neg_offset(asm, count)
                ; sub pointer, rax
            );
        }

        Change(count) => {
            dynasm!(asm
                ; add [pointer], BYTE u8_to_i8(count)
            );
        }

        In => {
            dynasm!(asm
                ; mov rax, QWORD rts::RtsState::read as _
                ; mov rcx, rts
                ; sub rsp, BYTE 0x28
                ; call rax
                ; add rsp, BYTE 0x28
                ; mov [pointer], al
            );
        }

        Out => {
            dynasm!(asm
                ; mov rax, QWORD rts::RtsState::write as _
                ; mov rcx, rts
                ; xor rdx, rdx
                ; mov dl, [pointer]
                ; sub rsp, BYTE 0x28
                ; call rax
                ; add rsp, BYTE 0x28
            );
        }

        SetZero => {
            dynasm!(asm
                ; mov BYTE [pointer], 0
            )
        }

        FindZeroRight(skip) => {
            dynasm!(asm
                ; jmp >end_loop
                ; begin_loop:
                ;; load_pos_offset(asm, skip)
                ; add pointer, rax
                ; end_loop:
                ; cmp BYTE [pointer], 0
                ; jnz <begin_loop
            )
        }

        FindZeroLeft(skip) => {
            dynasm!(asm
                ; jmp >end_loop
                ; begin_loop:
                ;; load_neg_offset(asm, skip)
                ; sub pointer, rax
                ; end_loop:
                ; cmp BYTE [pointer], 0
                ; jnz <begin_loop
            )
        }

        OffsetAddRight(offset) => {
            dynasm!(asm
                ; cmp BYTE [pointer], 0
                ; jz >skip
                ;; load_pos_offset(asm, offset)
                ; mov cl, BYTE [pointer]
                ; mov BYTE [pointer], 0
                ; add BYTE [pointer + rax], cl
                ; skip:
            );
        }

        OffsetAddLeft(offset) => {
            dynasm!(asm
                ; cmp BYTE [pointer], 0
                ; jz >skip
                ;; load_neg_offset(asm, offset)
                ; mov cl, BYTE [pointer]
                ; mov BYTE [pointer], 0
                ; neg rax
                ; add BYTE [pointer + rax], cl
                ; skip:
            );
        }

        Loop(ref body) => {
            let begin_label = asm.new_dynamic_label();
            let end_label   = asm.new_dynamic_label();

            dynasm!(asm
                ; jmp =>end_label
                ; =>begin_label
            );

            compile_sequence(asm, body);

            dynasm!(asm
                ; =>end_label
                ; cmp BYTE [pointer], 0
                ; jnz =>begin_label
            );
        }
    }
}

fn load_pos_offset(asm: &mut Assembler, offset: usize) {
    dynasm!(asm
        ; mov rax, QWORD offset as i64
    );

    if cfg!(not(feature = "omit_bounds_checks")) {
        dynasm!(asm
            ; mov rcx, mem_limit
            ; sub rcx, pointer
            ; cmp rcx, rax
            ; jle ->overflow
        );
    }
}

fn load_neg_offset(asm: &mut Assembler, offset: usize) {
    dynasm!(asm
        ; mov rax, QWORD offset as i64
    );

    if cfg!(not(feature = "omit_bounds_checks")) {
        dynasm!(asm
            ; mov rcx, pointer
            ; sub rcx, mem_start
            ; cmp rcx, rax
            ; jl ->underflow
        );
    }
}

fn u8_to_i8(n: u8) -> i8 {
    let mut n = n as isize % 256;
    if n > 127 { n -= 256 };
    n as i8
}
<|endoftext|>


<commit_before>extern crate std;
use std::cmp::max;
use std::vec::Vec;

// This struct is used to store our items that we want in our knap-sack.
//
// Show is for displaying the fields.
// allow(dead_code) removes a dead code warning when the name of the struct is not
// used (as in this case happens in the tests)
struct Want<'a> {
    #[allow(dead_code)]
    name: &'a str,
    weight: uint,
    value: uint
}

// Global, immutable allocation of our items. This is so we can reference
// this in multiple functions.
static items : &'static [Want<'static>] = &[
    Want {name: "map",                    weight: 9,   value: 150},
    Want {name: "compass",                weight: 13,  value: 35},
    Want {name: "water",                  weight: 153, value: 200},
    Want {name: "sandwich",               weight: 50,  value: 160},
    Want {name: "glucose",                weight: 15,  value: 60},
    Want {name: "tin",                    weight: 68,  value: 45},
    Want {name: "banana",                 weight: 27,  value: 60},
    Want {name: "apple",                  weight: 39,  value: 40},
    Want {name: "cheese",                 weight: 23,  value: 30},
    Want {name: "beer",                   weight: 52,  value: 10},
    Want {name: "suntancream",            weight: 11,  value: 70},
    Want {name: "camera",                 weight: 32,  value: 30},
    Want {name: "T-shirt",                weight: 24,  value: 15},
    Want {name: "trousers",               weight: 48,  value: 10},
    Want {name: "umbrella",               weight: 73,  value: 40},
    Want {name: "waterproof trousers",    weight: 42,  value: 70},
    Want {name: "waterproof overclothes", weight: 43,  value: 75},
    Want {name: "note-case",              weight: 22,  value: 80},
    Want {name: "sunglasses",             weight: 7,   value: 20},
    Want {name: "towel",                  weight: 18,  value: 12},
    Want {name: "socks",                  weight: 4,   value: 50},
    Want {name: "book",                   weight: 30,  value: 10}
];

// This is a bottom-up dynamic programming solution to the 0-1 knap-sack problem.
//      maximize value
//      subject to weights <= max_weight
fn knap_01_dp<'a>(xs: &[Want<'a>], max_weight: uint) -> Vec<Want<'a>> {

    // Save this value, so we don't have to make repeated calls.
    let xs_len = xs.len();

    // Imagine we wrote a recursive function(item, max_weight) that returns a
    // uint corresponding to the maximum cumulative value by considering a
    // subset of items such that the combined weight <= max_weight.
    //
    // fn best_value(item: uint, max_weight: uint) -> uint{
    //     if item == 0 {
    //         return 0;
    //     }
    //     if xs[item - 1].weight > max_weight {
    //         return best_value(item - 1, max_weight, xs);
    //     }
    //     return max(best_value(item - 1, max_weight, xs),
    //                best_value(item - 1, max_weight - xs[item - 1].weight, xs)
    //                + xs[item - 1].value);
    //     }
    //
    // best_value(xs_len, max_weight) is equal to the maximum value that we
    // can add to the bag.
    //
    // The problem with using this function is that it performs redudant
    // calculations.
    //
    // The dynamic programming solution is to precompute all of the values we
    // need and put them into a 2D array.
    //
    // In a similar vein, the top-down solution would be to memoize the
    // function then compute the results on demand.

    let zero_vec = Vec::from_elem(max_weight + 1, 0 as uint);
    let mut best_value = Vec::from_elem(xs_len + 1, zero_vec);

    // loop over the items
    for i in range(0, xs_len) {
        // loop over the weights
        for w in range(1, max_weight + 1) {
            // do we have room in our knapsack?
            if xs[i].weight > w {
                // if we don't, then we'll say that the value doesn't change
                // when considering this item
                *best_value.get_mut(i + 1).get_mut(w) = best_value[i][w].clone();
            } else {
                // if we do, then we have to see if the value we gain by adding
                // the item, given the weight, is better than not adding the item
                *best_value.get_mut(i + 1).get_mut(w) =
                    max(best_value[i][w].clone(),
                        best_value[i][w - xs[i].weight] + xs[i].value);
            }
        }
    }

    // a variable representing the weight left in the bag
    let mut left_weight = max_weight.clone();

    // a possibly over-allocated dynamically sized vector to push results to
    let mut result = Vec::with_capacity(xs_len);

    // we built up the solution space through a forward pass over the data,
    // now we have to traverse backwards to get the solution
    for i in range(1, xs_len+1).rev() {
        // We can check if an item should be added to the knap-sack by comparing
        // best_value with and without this item. If best_value added this
        // item then so should we.
        if best_value[i][left_weight] != best_value[i - 1][left_weight] {
            result.push(xs[i - 1]);
            // we remove the weight of the object from the remaining weight
            // we can add to the bag
            left_weight -= xs[i - 1].weight;
        }
    }

    return result;
}

#[cfg(not(test))]
fn main () {
    let xs = knap_01_dp(items, 400);

    // Print the items. We have to reverse the order because we solved the
    // problem backward.
    for i in xs.iter().rev() {
        println!("Item: {}, Weight: {}, Value: {}", i.name, i.weight, i.value);
    }

    // Print the sum of weights.
    let weights = xs.iter().fold(0, |a, &b| a + b.weight);
    println!("Total Weight: {}", weights);

    // Print the sum of the values.
    let values = xs.iter().fold(0, |a, &b| a + b.value);
    println!("Total Value: {}", values);

}

#[test]
fn test_dp_results() {
    let dp_results = knap_01_dp(items, 400);
    let dp_weights= dp_results.iter().fold(0, |a, &b| a + b.weight);
    let dp_values = dp_results.iter().fold(0, |a, &b| a + b.value);
    assert_eq!(dp_weights, 396);
    assert_eq!(dp_values, 1030);
}
<commit_msg>Fix knapsack<commit_after>use std::cmp::max;

// This struct is used to store our items that we want in our knap-sack.
//
// Show is for displaying the fields.
// allow(dead_code) removes a dead code warning when the name of the struct is not
// used (as in this case happens in the tests)
struct Want<'a> {
    #[allow(dead_code)]
    name: &'a str,
    weight: uint,
    value: uint
}

// Global, immutable allocation of our items. This is so we can reference
// this in multiple functions.
static items : &'static [Want<'static>] = &[
    Want {name: "map",                    weight: 9,   value: 150},
    Want {name: "compass",                weight: 13,  value: 35},
    Want {name: "water",                  weight: 153, value: 200},
    Want {name: "sandwich",               weight: 50,  value: 160},
    Want {name: "glucose",                weight: 15,  value: 60},
    Want {name: "tin",                    weight: 68,  value: 45},
    Want {name: "banana",                 weight: 27,  value: 60},
    Want {name: "apple",                  weight: 39,  value: 40},
    Want {name: "cheese",                 weight: 23,  value: 30},
    Want {name: "beer",                   weight: 52,  value: 10},
    Want {name: "suntancream",            weight: 11,  value: 70},
    Want {name: "camera",                 weight: 32,  value: 30},
    Want {name: "T-shirt",                weight: 24,  value: 15},
    Want {name: "trousers",               weight: 48,  value: 10},
    Want {name: "umbrella",               weight: 73,  value: 40},
    Want {name: "waterproof trousers",    weight: 42,  value: 70},
    Want {name: "waterproof overclothes", weight: 43,  value: 75},
    Want {name: "note-case",              weight: 22,  value: 80},
    Want {name: "sunglasses",             weight: 7,   value: 20},
    Want {name: "towel",                  weight: 18,  value: 12},
    Want {name: "socks",                  weight: 4,   value: 50},
    Want {name: "book",                   weight: 30,  value: 10}
];

// This is a bottom-up dynamic programming solution to the 0-1 knap-sack problem.
//      maximize value
//      subject to weights <= max_weight
fn knap_01_dp<'a>(xs: &[Want<'a>], max_weight: uint) -> Vec<Want<'a>> {

    // Save this value, so we don't have to make repeated calls.
    let xs_len = xs.len();

    // Imagine we wrote a recursive function(item, max_weight) that returns a
    // uint corresponding to the maximum cumulative value by considering a
    // subset of items such that the combined weight <= max_weight.
    //
    // fn best_value(item: uint, max_weight: uint) -> uint{
    //     if item == 0 {
    //         return 0;
    //     }
    //     if xs[item - 1].weight > max_weight {
    //         return best_value(item - 1, max_weight, xs);
    //     }
    //     return max(best_value(item - 1, max_weight, xs),
    //                best_value(item - 1, max_weight - xs[item - 1].weight, xs)
    //                + xs[item - 1].value);
    //     }
    //
    // best_value(xs_len, max_weight) is equal to the maximum value that we
    // can add to the bag.
    //
    // The problem with using this function is that it performs redudant
    // calculations.
    //
    // The dynamic programming solution is to precompute all of the values we
    // need and put them into a 2D array.
    //
    // In a similar vein, the top-down solution would be to memoize the
    // function then compute the results on demand.

    let zero_vec = Vec::from_elem(max_weight + 1, 0 as uint);
    let mut best_value = Vec::from_elem(xs_len + 1, zero_vec);

    // loop over the items
    for i in range(0, xs_len) {
        // loop over the weights
        for w in range(1, max_weight + 1) {
            // do we have room in our knapsack?
            if xs[i].weight > w {
                // if we don't, then we'll say that the value doesn't change
                // when considering this item
                *best_value.get_mut(i + 1).get_mut(w) = best_value[i][w].clone();
            } else {
                // if we do, then we have to see if the value we gain by adding
                // the item, given the weight, is better than not adding the item
                *best_value.get_mut(i + 1).get_mut(w) =
                    max(best_value[i][w].clone(),
                        best_value[i][w - xs[i].weight] + xs[i].value);
            }
        }
    }

    // a variable representing the weight left in the bag
    let mut left_weight = max_weight.clone();

    // a possibly over-allocated dynamically sized vector to push results to
    let mut result = Vec::with_capacity(xs_len);

    // we built up the solution space through a forward pass over the data,
    // now we have to traverse backwards to get the solution
    for i in range(1, xs_len+1).rev() {
        // We can check if an item should be added to the knap-sack by comparing
        // best_value with and without this item. If best_value added this
        // item then so should we.
        if best_value[i][left_weight] != best_value[i - 1][left_weight] {
            result.push(xs[i - 1]);
            // we remove the weight of the object from the remaining weight
            // we can add to the bag
            left_weight -= xs[i - 1].weight;
        }
    }

    return result;
}

#[cfg(not(test))]
fn main () {
    let xs = knap_01_dp(items, 400);

    // Print the items. We have to reverse the order because we solved the
    // problem backward.
    for i in xs.iter().rev() {
        println!("Item: {}, Weight: {}, Value: {}", i.name, i.weight, i.value);
    }

    // Print the sum of weights.
    let weights = xs.iter().fold(0, |a, &b| a + b.weight);
    println!("Total Weight: {}", weights);

    // Print the sum of the values.
    let values = xs.iter().fold(0, |a, &b| a + b.value);
    println!("Total Value: {}", values);

}

#[test]
fn test_dp_results() {
    let dp_results = knap_01_dp(items, 400);
    let dp_weights= dp_results.iter().fold(0, |a, &b| a + b.weight);
    let dp_values = dp_results.iter().fold(0, |a, &b| a + b.value);
    assert_eq!(dp_weights, 396);
    assert_eq!(dp_values, 1030);
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// 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; version
// 2.1 of the License.
//
// 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
//

use libimagstore::store::Store;
use libimagerror::trace::trace_error;
use std::error::Error;
use std::ops::Deref;
use std::ops::DerefMut;

use ruru::{Class, Object, AnyObject, Boolean, RString, VM, Hash, NilClass, VerifiedObject};

use ruby_utils::IntoToml;
use toml_utils::IntoRuby;
use util::Wrap;
use util::Unwrap;

use storeid::RStoreId;
use entry::RFileLockEntry;
use cache::StoreHandle;

wrappable_struct!(StoreHandle, StoreWrapper, STORE_WRAPPER);
class!(RStore);
impl_wrap!(StoreHandle, STORE_WRAPPER);
impl_unwrap!(RStore, StoreHandle, STORE_WRAPPER);
impl_verified_object!(RStore);

macro_rules! call_on_store_by_handle {
    {
        $store_handle:ident named $name:ident inside $operation:block
    }=> {{
        call_on_store_by_handle! {
            $store_handle
            named $name
            inside $operation
            on fail return NilClass::new().to_any_object()
        }
    }};

    {
        $store_handle:ident named $name:ident inside $operation:block on fail return $ex:expr
    } => {{
        use cache::RUBY_STORE_CACHE;

        let arc = RUBY_STORE_CACHE.clone();
        {
            let lock = arc.lock();
            match lock {
                Ok(mut hm) => {
                    match hm.get($store_handle) {
                        Some($name) => { $operation },
                        None => {
                            VM::raise(Class::from_existing("RuntimeError"),
                                    "Tried to operate on non-existing object");
                            $ex
                        }
                    }
                },
                Err(e) => {
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                    $ex
                }
            }
        }
    }};
}

macro_rules! call_on_store {
    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        $fle_name:ident <- fetch $fle_handle_name:ident
        operation $operation:block
    } => {
        call_on_store! {
            $store_name <- $itself wrapped inside $wrapper,
            $fle_name <- fetch $fle_handle_name,
            operation $operation,
            on fail return NilClass::new()
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        $fle_name:ident <- fetch $fle_handle_name:ident,
        operation $operation:block,
        on fail return $fail_expr:expr
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! {
            handle named $store_name inside {
                let $fle_name = match $store_name.get($fle_handle_name) {
                    Ok(Some(fle)) => fle,
                    Ok(None) => {
                        VM::raise(Class::from_existing("RuntimeError"), "Obj does not exist");
                        return $fail_expr
                    },
                    Err(e) => {
                        VM::raise(Class::from_existing("RuntimeError"), e.description());
                        return $fail_expr
                    },
                };
                $operation
            }
            on fail return $fail_expr
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        operation $operation:block,
        on fail return $fail_expr:expr
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! {
            handle named $store_name inside $operation on fail return $fail_expr
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        operation $block
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! { handle named $name inside $operation }
    };
}

methods!(
    RStore,
    itself,

    // Create an FileLockEntry in the store
    //
    // # Returns:
    //
    // On success: A RFileLockEntry
    // On failure: Nil
    // On error: Nil + Exception
    //
    fn create(id: RStoreId) -> AnyObject {
        unimplemented!()
    }

    // Retrieve an FileLockEntry from the store
    //
    // # Returns:
    //
    // On success: A RFileLockEntry
    // On error: Nil + Exception
    //
    fn retrieve(id: RStoreId) -> AnyObject {
        unimplemented!()
    }

    // Get an FileLockEntry from the store
    //
    // # Returns:
    //
    // On success, if there is some: A RFileLockEntry
    // On success, if there is none: Nil
    // On error: Nil + Exception
    //
    fn get(sid: RStoreId) -> AnyObject {
        unimplemented!()
    }

    // Get all FileLockEntry of a module from the store
    //
    // # Returns:
    //
    // On success: A Array[RFileLockEntry]
    // On error: Nil + Exception
    //
    fn retrieve_for_module(name: RString) -> AnyObject {
        unimplemented!()
    }

    // Update a FileLockEntry in the store
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn update(fle: RFileLockEntry) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.update(real_fle) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Delete a FileLockEntry from the store
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn delete(sid: RStoreId) -> NilClass {
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                if let Err(e) = store.delete(sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Save a FileLockEntry in a new path inside the store, keep the RFileLockEntry
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn save_to(fle: RFileLockEntry, sid: RStoreId) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.save_to(&real_fle, sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Save a FileLockEntry in a new path inside the store, move the RFileLockEntry
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn save_as(fle: RFileLockEntry, sid: RStoreId) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.save_as(real_fle, sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Move one entry in the store to another place, by its ID
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn move_by_id(old: RStoreId, nw: RStoreId) -> NilClass {
        let old = typecheck!(old).unwrap().clone();
        let nw  = typecheck!(nw).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                if let Err(e) = store.move_by_id(old, nw) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Get the path of the store object
    //
    // # Returns:
    //
    // A RString
    //
    fn path() -> RString {
        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                store.path()
                    .clone()
                    .to_str()
                    .map(RString::new)
                    .unwrap_or(RString::new(""))
            },
            on fail return RString::new("")
        }
    }

);

pub fn setup() {
    unimplemented!()
}
<commit_msg>Impl Store::get() interface function<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// 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; version
// 2.1 of the License.
//
// 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
//

use libimagstore::store::Store;
use libimagerror::trace::trace_error;
use std::error::Error;
use std::ops::Deref;
use std::ops::DerefMut;

use ruru::{Class, Object, AnyObject, Boolean, RString, VM, Hash, NilClass, VerifiedObject};

use ruby_utils::IntoToml;
use toml_utils::IntoRuby;
use util::Wrap;
use util::Unwrap;

use storeid::RStoreId;
use entry::RFileLockEntry;
use cache::StoreHandle;

wrappable_struct!(StoreHandle, StoreWrapper, STORE_WRAPPER);
class!(RStore);
impl_wrap!(StoreHandle, STORE_WRAPPER);
impl_unwrap!(RStore, StoreHandle, STORE_WRAPPER);
impl_verified_object!(RStore);

macro_rules! call_on_store_by_handle {
    {
        $store_handle:ident named $name:ident inside $operation:block
    }=> {{
        call_on_store_by_handle! {
            $store_handle
            named $name
            inside $operation
            on fail return NilClass::new().to_any_object()
        }
    }};

    {
        $store_handle:ident named $name:ident inside $operation:block on fail return $ex:expr
    } => {{
        use cache::RUBY_STORE_CACHE;

        let arc = RUBY_STORE_CACHE.clone();
        {
            let lock = arc.lock();
            match lock {
                Ok(mut hm) => {
                    match hm.get($store_handle) {
                        Some($name) => { $operation },
                        None => {
                            VM::raise(Class::from_existing("RuntimeError"),
                                    "Tried to operate on non-existing object");
                            $ex
                        }
                    }
                },
                Err(e) => {
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                    $ex
                }
            }
        }
    }};
}

macro_rules! call_on_store {
    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        $fle_name:ident <- fetch $fle_handle_name:ident
        operation $operation:block
    } => {
        call_on_store! {
            $store_name <- $itself wrapped inside $wrapper,
            $fle_name <- fetch $fle_handle_name,
            operation $operation,
            on fail return NilClass::new()
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        $fle_name:ident <- fetch $fle_handle_name:ident,
        operation $operation:block,
        on fail return $fail_expr:expr
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! {
            handle named $store_name inside {
                let $fle_name = match $store_name.get($fle_handle_name) {
                    Ok(Some(fle)) => fle,
                    Ok(None) => {
                        VM::raise(Class::from_existing("RuntimeError"), "Obj does not exist");
                        return $fail_expr
                    },
                    Err(e) => {
                        VM::raise(Class::from_existing("RuntimeError"), e.description());
                        return $fail_expr
                    },
                };
                $operation
            }
            on fail return $fail_expr
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        operation $operation:block,
        on fail return $fail_expr:expr
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! {
            handle named $store_name inside $operation on fail return $fail_expr
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        operation $block
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! { handle named $name inside $operation }
    };
}

methods!(
    RStore,
    itself,

    // Create an FileLockEntry in the store
    //
    // # Returns:
    //
    // On success: A RFileLockEntry
    // On failure: Nil
    // On error: Nil + Exception
    //
    fn create(id: RStoreId) -> AnyObject {
        unimplemented!()
    }

    // Retrieve an FileLockEntry from the store
    //
    // # Returns:
    //
    // On success: A RFileLockEntry
    // On error: Nil + Exception
    //
    fn retrieve(id: RStoreId) -> AnyObject {
        unimplemented!()
    }

    // Get an FileLockEntry from the store
    //
    // # Returns:
    //
    // On success, if there is some: A RFileLockEntry
    // On success, if there is none: Nil
    // On error: Nil + Exception
    //
    fn get(sid: RStoreId) -> AnyObject {
        use entry::FileLockEntryHandle;
        let sid = typecheck!(sid or return any NilClass::new()).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                match store.get(sid.clone()) {
                    Err(e) => {
                        trace_error(&e);
                        VM::raise(Class::from_existing("RuntimeError"), e.description());
                        NilClass::new().to_any_object()
                    },
                    Ok(None) => NilClass::new().to_any_object(),
                    Ok(Some(entry)) => {
                        // Take the location (StoreId) of the entry (we know it exists... so this
                        // is fine) and wrap it into a RFileLockEntry which is then returned to the
                        // user (as handle)
                        let sid = entry.get_location().clone();
                        let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
                        FileLockEntryHandle::new(store_handle, sid).wrap()
                    },
                }
            },
            on fail return NilClass::new().to_any_object()
        }
    }

    // Get all FileLockEntry of a module from the store
    //
    // # Returns:
    //
    // On success: A Array[RFileLockEntry]
    // On error: Nil + Exception
    //
    fn retrieve_for_module(name: RString) -> AnyObject {
        unimplemented!()
    }

    // Update a FileLockEntry in the store
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn update(fle: RFileLockEntry) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.update(real_fle) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Delete a FileLockEntry from the store
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn delete(sid: RStoreId) -> NilClass {
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                if let Err(e) = store.delete(sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Save a FileLockEntry in a new path inside the store, keep the RFileLockEntry
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn save_to(fle: RFileLockEntry, sid: RStoreId) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.save_to(&real_fle, sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Save a FileLockEntry in a new path inside the store, move the RFileLockEntry
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn save_as(fle: RFileLockEntry, sid: RStoreId) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.save_as(real_fle, sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Move one entry in the store to another place, by its ID
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn move_by_id(old: RStoreId, nw: RStoreId) -> NilClass {
        let old = typecheck!(old).unwrap().clone();
        let nw  = typecheck!(nw).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                if let Err(e) = store.move_by_id(old, nw) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Get the path of the store object
    //
    // # Returns:
    //
    // A RString
    //
    fn path() -> RString {
        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                store.path()
                    .clone()
                    .to_str()
                    .map(RString::new)
                    .unwrap_or(RString::new(""))
            },
            on fail return RString::new("")
        }
    }

);

pub fn setup() {
    unimplemented!()
}
<|endoftext|>