<commit_before>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

use prost::Message;
use tink_core::TinkError;

#[test]
fn test_ecdsa_key_templates() {
    struct FlagTest {
        tc_name: &'static str,
        type_url: &'static str,
        sig_template: tink_proto::KeyTemplate,
        curve_type: tink_proto::EllipticCurveType,
        hash_type: tink_proto::HashType,
        sig_encoding: tink_proto::EcdsaSignatureEncoding,
        prefix_type: tink_proto::OutputPrefixType,
    };
    let flag_tests = vec![
        FlagTest {
            tc_name: "P-256 with SHA256, DER format and TINK output prefix",
            type_url: tink_tests::ECDSA_SIGNER_TYPE_URL,
            sig_template: tink_signature::ecdsa_p256_key_template(),
            curve_type: tink_proto::EllipticCurveType::NistP256,
            hash_type: tink_proto::HashType::Sha256,
            sig_encoding: tink_proto::EcdsaSignatureEncoding::Der,
            prefix_type: tink_proto::OutputPrefixType::Tink,
        },
        FlagTest {
            tc_name: "P-384 with SHA512, DER format and TINK output prefix",
            type_url: tink_tests::ECDSA_SIGNER_TYPE_URL,
            sig_template: tink_signature::ecdsa_p384_key_template(),
            curve_type: tink_proto::EllipticCurveType::NistP384,
            hash_type: tink_proto::HashType::Sha512,
            sig_encoding: tink_proto::EcdsaSignatureEncoding::Der,
            prefix_type: tink_proto::OutputPrefixType::Tink,
        },
        FlagTest {
            tc_name: "P-521 with SHA512, DER format and TINK output prefix",
            type_url: tink_tests::ECDSA_SIGNER_TYPE_URL,
            sig_template: tink_signature::ecdsa_p521_key_template(),
            curve_type: tink_proto::EllipticCurveType::NistP521,
            hash_type: tink_proto::HashType::Sha512,
            sig_encoding: tink_proto::EcdsaSignatureEncoding::Der,
            prefix_type: tink_proto::OutputPrefixType::Tink,
        },
        FlagTest {
            tc_name: "P-256 with SHA256, DER format and RAW output prefix",
            type_url: tink_tests::ECDSA_SIGNER_TYPE_URL,
            sig_template: tink_signature::ecdsa_p256_key_without_prefix_template(),
            curve_type: tink_proto::EllipticCurveType::NistP256,
            hash_type: tink_proto::HashType::Sha256,
            sig_encoding: tink_proto::EcdsaSignatureEncoding::Der,
            prefix_type: tink_proto::OutputPrefixType::Raw,
        },
        FlagTest {
            tc_name: "P-384 with SHA512, DER format and RAW output prefix",
            type_url: tink_tests::ECDSA_SIGNER_TYPE_URL,
            sig_template: tink_signature::ecdsa_p384_key_without_prefix_template(),
            curve_type: tink_proto::EllipticCurveType::NistP384,
            hash_type: tink_proto::HashType::Sha512,
            sig_encoding: tink_proto::EcdsaSignatureEncoding::Der,
            prefix_type: tink_proto::OutputPrefixType::Raw,
        },
        FlagTest {
            tc_name: "P-521 with SHA512, DER format and RAW output prefix",
            type_url: tink_tests::ECDSA_SIGNER_TYPE_URL,
            sig_template: tink_signature::ecdsa_p521_key_without_prefix_template(),
            curve_type: tink_proto::EllipticCurveType::NistP521,
            hash_type: tink_proto::HashType::Sha512,
            sig_encoding: tink_proto::EcdsaSignatureEncoding::Der,
            prefix_type: tink_proto::OutputPrefixType::Raw,
        },
        FlagTest {
            tc_name: "P-256 with SHA256, P1363 format and TINK output prefix",
            type_url: tink_tests::ECDSA_SIGNER_TYPE_URL,
            sig_template: tink_signature::ecdsa_p256_key_p1363_template(),
            curve_type: tink_proto::EllipticCurveType::NistP256,
            hash_type: tink_proto::HashType::Sha256,
            sig_encoding: tink_proto::EcdsaSignatureEncoding::IeeeP1363,
            prefix_type: tink_proto::OutputPrefixType::Tink,
        },
    ];

    for tt in flag_tests {
        let tc_name = tt.tc_name;
        check_ecdsa_key_template(
            &tt.sig_template,
            tt.type_url,
            tt.hash_type,
            tt.curve_type,
            tt.sig_encoding,
            tt.prefix_type,
        )
        .unwrap_or_else(|e| panic!("failed {}: {}", tc_name, e));
    }
}

#[test]
fn test_ed25519_key_templates() {
    struct FlagTest {
        tc_name: &'static str,
        type_url: &'static str,
        sig_template: tink_proto::KeyTemplate,
        prefix_type: tink_proto::OutputPrefixType,
    };
    let flag_tests = vec![
        FlagTest {
            tc_name: "ED25519 with TINK output prefix",
            type_url: tink_tests::ED25519_SIGNER_TYPE_URL,
            sig_template: tink_signature::ed25519_key_template(),
            prefix_type: tink_proto::OutputPrefixType::Tink,
        },
        FlagTest {
            tc_name: "ED25519 with RAW output prefix",
            type_url: tink_tests::ED25519_SIGNER_TYPE_URL,
            sig_template: tink_signature::ed25519_key_without_prefix_template(),
            prefix_type: tink_proto::OutputPrefixType::Raw,
        },
    ];

    for tt in flag_tests {
        let tc_name = tt.tc_name;
        check_key_type_and_output_prefix(&tt.sig_template, tt.type_url, tt.prefix_type)
            .unwrap_or_else(|e| panic!("failed {}: {}", tc_name, e));
    }
}

fn check_ecdsa_key_template(
    template: &tink_proto::KeyTemplate,
    type_url: &str,
    hash_type: tink_proto::HashType,
    curve: tink_proto::EllipticCurveType,
    encoding: tink_proto::EcdsaSignatureEncoding,
    prefix_type: tink_proto::OutputPrefixType,
) -> Result<(), TinkError> {
    check_key_type_and_output_prefix(template, type_url, prefix_type)?;

    let format = tink_proto::EcdsaKeyFormat::decode(template.value.as_ref())
        .map_err(|_| TinkError::new("cannot unmarshal key format"))?;

    let params = format
        .params
        .ok_or_else(|| TinkError::new("missing parameters"))?;
    if params.hash_type != hash_type as i32 {
        return Err(format!(
            "incorrect hash type: expect {:?}, got {}",
            hash_type, params.hash_type
        )
        .into());
    }

    if params.curve != curve as i32 {
        return Err(format!("incorrect curve: expect {:?}, got {}", curve, params.curve).into());
    }

    if params.encoding != encoding as i32 {
        return Err(format!(
            "incorrect encoding: expect {:?}, got {}",
            encoding, params.encoding
        )
        .into());
    }

    Ok(())
}

fn check_key_type_and_output_prefix(
    template: &tink_proto::KeyTemplate,
    type_url: &str,
    prefix_type: tink_proto::OutputPrefixType,
) -> Result<(), TinkError> {
    if template.type_url != type_url {
        return Err(format!(
            "incorrect typeurl: expect {}, got {}",
            type_url, template.type_url
        )
        .into());
    }

    if template.output_prefix_type != prefix_type as i32 {
        return Err(format!(
            "incorrect outputPrefixType: expect: {:?}, got {}",
            prefix_type, template.output_prefix_type
        )
        .into());
    }

    Ok(())
}
<commit_msg>tink-signature: tweak key template test<commit_after>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

use tink_core::TinkError;

#[test]
fn test_key_templates() {
    tink_signature::init();
    let test_cases = vec![
        (
            "ECDSA_P256",
            tink_signature::ecdsa_p256_key_template(),
            true,
        ),
        (
            "ECDSA_P384",
            tink_signature::ecdsa_p384_key_template(),
            false,
        ),
        (
            "ECDSA_P521",
            tink_signature::ecdsa_p521_key_template(),
            false,
        ),
        (
            "ECDSA_P256_IEEE_P1363",
            tink_signature::ecdsa_p256_key_p1363_template(),
            true,
        ),
        ("ED25519", tink_signature::ed25519_key_template(), true),
    ];
    for (name, template, supported) in test_cases {
        let want = tink_tests::key_template_proto("signature", name).unwrap();
        assert_eq!(want, template);
        // TODO(#16): more ECDSA curves
        if supported {
            assert!(test_sign_verify(&template).is_ok());
        }
    }
}

#[test]
fn test_no_prefix_key_templates() {
    tink_signature::init();
    let test_cases = vec![
        (
            "ECDSA_P256",
            tink_signature::ecdsa_p256_key_without_prefix_template(),
            true,
        ),
        (
            "ECDSA_P384",
            tink_signature::ecdsa_p384_key_without_prefix_template(),
            false,
        ),
        (
            "ECDSA_P521",
            tink_signature::ecdsa_p521_key_without_prefix_template(),
            false,
        ),
        (
            "ED25519",
            tink_signature::ed25519_key_without_prefix_template(),
            true,
        ),
    ];
    for (name, template, supported) in test_cases {
        let mut want = tink_tests::key_template_proto("signature", name).unwrap();
        want.output_prefix_type = tink_proto::OutputPrefixType::Raw as i32;
        assert_eq!(want, template);
        // TODO(#16): more ECDSA curves
        if supported {
            assert!(test_sign_verify(&template).is_ok());
        }
    }
}

fn test_sign_verify(template: &tink_proto::KeyTemplate) -> Result<(), TinkError> {
    let private_handle = tink_core::keyset::Handle::new(template).unwrap();
    let signer = tink_signature::new_signer(&private_handle).unwrap();

    let msg = b"this data needs to be signed";
    let sig = signer.sign(&msg[..]).unwrap();

    let public_handle = private_handle.public().unwrap();
    let verifier = tink_signature::new_verifier(&public_handle).unwrap();
    verifier.verify(&sig, &msg[..])
}
<|endoftext|>


<commit_before>use std::mem;
use super::gl;
use super::gl_lib::types::*;
use super::{Buffer, ArrayBufferBinder, ElementArrayBufferBinder};
use super::{Shader, ShaderType};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder
        }
    }

    pub fn clear_color(&mut self, color: super::Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: super::BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn vertex_attrib_pointer(&self,
                                 attrib: super::ProgramAttrib,
                                 components: i8,
                                 gl_type: super::DataType,
                                 normalized: bool,
                                 stride: usize,
                                 offset: usize)
    {
        unsafe {
            debug_assert!(1 <= components && components <= 4);

            let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
            gl::VertexAttribPointer(attrib.gl_index,
                                    components as GLint,
                                    gl_type as GLenum,
                                    gl_normalized,
                                    stride as GLsizei,
                                    offset as *const GLvoid);
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: super::ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
        }
    }

    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = mem::uninitialized();
            gl::GenBuffers(1, &mut id as *mut GLuint);
            Buffer::from_id(id)
        }
    }

    pub fn create_shader(&self, shader_type: ShaderType) -> Result<Shader, ()> {
        unsafe {
            let id = gl::CreateShader(shader_type as GLenum);
            if id > 0 {
                Ok(Shader::from_id(id))
            }
            else {
                Err(())
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}
<commit_msg>Add `Context.create_program()`<commit_after>use std::mem;
use super::gl;
use super::gl_lib::types::*;
use super::{Buffer, ArrayBufferBinder, ElementArrayBufferBinder};
use super::{Shader, ShaderType};
use super::Program;

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder
        }
    }

    pub fn clear_color(&mut self, color: super::Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: super::BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn vertex_attrib_pointer(&self,
                                 attrib: super::ProgramAttrib,
                                 components: i8,
                                 gl_type: super::DataType,
                                 normalized: bool,
                                 stride: usize,
                                 offset: usize)
    {
        unsafe {
            debug_assert!(1 <= components && components <= 4);

            let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
            gl::VertexAttribPointer(attrib.gl_index,
                                    components as GLint,
                                    gl_type as GLenum,
                                    gl_normalized,
                                    stride as GLsizei,
                                    offset as *const GLvoid);
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: super::ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
        }
    }

    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = mem::uninitialized();
            gl::GenBuffers(1, &mut id as *mut GLuint);
            Buffer::from_id(id)
        }
    }

    pub fn create_shader(&self, shader_type: ShaderType) -> Result<Shader, ()> {
        unsafe {
            let id = gl::CreateShader(shader_type as GLenum);
            if id > 0 {
                Ok(Shader::from_id(id))
            }
            else {
                Err(())
            }
        }
    }

    pub fn create_program(&self) -> Result<Program, ()> {
        unsafe {
            let id = gl::CreateProgram();
            if id > 0 {
                Ok(Program::from_id(id))
            }
            else {
                Err(())
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}
<|endoftext|>


<commit_before>#![allow(experimental)]

use std::io::{File,fs};
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;
use std::finally::Finally;

pub fn new(name: &str) {
    let muxed_dir = if muxed_dir_exists(&"muxed".to_string()) {
      Path::new(format!("{}/.muxed/", homedir_string()))
    } else {
      create_muxed_dir(&"muxed".to_string())
    };

    let path = format!("{}/{}", muxed_dir.display(), name);

    File::create(&Path::new(path));
}

fn create_muxed_dir(name: &String) -> Path {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    path.exists()
}

fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}

#[test]
#[should_fail]
fn new_doesnt_overwrite_existing_file() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        fs::unlink(path);
    })
}
<commit_msg>Only create the file if it doesn't already exist.<commit_after>#![allow(experimental)]

use std::io::{File,fs};
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;
use std::finally::Finally;

pub fn new(name: &str) {
    let muxed_dir = if muxed_dir_exists(&"muxed".to_string()) {
      Path::new(format!("{}/.muxed/", homedir_string()))
    } else {
      create_muxed_dir(&"muxed".to_string())
    };

    let path = &Path::new(format!("{}/{}", muxed_dir.display(), name));
    if !path.exists() {
      File::create(&Path::new(path));
    } else {
      println!("Project already exists.");
    }
}

fn create_muxed_dir(name: &String) -> Path {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    path.exists()
}

fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}

#[test]
#[should_fail]
fn new_doesnt_overwrite_existing_file() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        fs::unlink(path);
    })
}
<|endoftext|>


<commit_before>use error::Result;
use serde;
use std::{io, slice};

/// An optional Read trait for advanced Bincode usage.
///
/// It is highly recommended to use bincode with `io::Read` or `&[u8]` before
/// implementing a custom `BincodeRead`.
///
/// The forward_read_* methods are necessary because some byte sources want
/// to pass a long-lived borrow to the visitor and others want to pass a
/// transient slice.
pub trait BincodeRead<'storage>: io::Read {
    /// Check that the next `length` bytes are a valid string and pass
    /// it on to the serde reader.
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>;

    /// Transfer ownership of the next `length` bytes to the caller.
    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>>;

    /// Pass a slice of the next `length` bytes on to the serde reader.
    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>;
}

/// A BincodeRead implementation for byte slices
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub struct SliceReader<'storage> {
    slice: &'storage [u8],
}

/// A BincodeRead implementation for io::Readers
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub struct IoReader<R> {
    reader: R,
    temp_buffer: Vec<u8>,
}

impl<'storage> SliceReader<'storage> {
    /// Constructs a slice reader
    pub fn new(bytes: &'storage [u8]) -> SliceReader<'storage> {
        SliceReader { slice: bytes }
    }

    #[inline(always)]
    fn get_byte_slice(&mut self, length: usize) -> Result<&'storage [u8]> {
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }

        let s = &self.slice[..length];
        self.slice = &self.slice[length..];
        Ok(s)
    }
}

impl<R> IoReader<R> {
    /// Constructs an IoReadReader
    pub fn new(r: R) -> IoReader<R> {
        IoReader {
            reader: r,
            temp_buffer: vec![],
        }
    }
}

impl<'storage> io::Read for SliceReader<'storage> {
    #[inline(always)]
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        (&mut self.slice).read(out)
    }
    #[inline(always)]
    fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> {
        (&mut self.slice).read_exact(out)
    }
}

impl<R: io::Read> io::Read for IoReader<R> {
    #[inline(always)]
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        self.reader.read(out)
    }
    #[inline(always)]
    fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> {
        self.reader.read_exact(out)
    }
}

impl<'storage> SliceReader<'storage> {
    #[inline(always)]
    fn unexpected_eof() -> Box<::ErrorKind> {
        return Box::new(::ErrorKind::Io(io::Error::new(
            io::ErrorKind::UnexpectedEof,
            "",
        )));
    }
}

impl<'storage> BincodeRead<'storage> for SliceReader<'storage> {
    #[inline(always)]
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>,
    {
        use ErrorKind;
        let string = match ::std::str::from_utf8(self.get_byte_slice(length)?) {
            Ok(s) => s,
            Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()),
        };
        visitor.visit_borrowed_str(string)
    }

    #[inline(always)]
    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        self.get_byte_slice(length).map(|x| x.to_vec())
    }

    #[inline(always)]
    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>,
    {
        visitor.visit_borrowed_bytes(self.get_byte_slice(length)?)
    }
}

impl<R> IoReader<R>
where
    R: io::Read,
{
    fn fill_buffer(&mut self, length: usize) -> Result<()> {
        // We first reserve the space needed in our buffer.
        let current_length = self.temp_buffer.len();
        if length > current_length {
            self.temp_buffer.reserve_exact(length - current_length);
        }

        // Then create a slice with the length as our desired length. This is
        // safe as long as we only write (no reads) to this buffer, because
        // `reserve_exact` above has allocated this space.
        let buf = unsafe {
            slice::from_raw_parts_mut(self.temp_buffer.as_mut_ptr(), length)
        };

        // This method is assumed to properly handle slices which include
        // uninitialized bytes (as ours does). See discussion at the link below.
        // https://github.com/servo/bincode/issues/260
        self.reader.read_exact(buf)?;

        // Only after `read_exact` successfully returns do we set the buffer
        // length. By doing this after the call to `read_exact`, we can avoid
        // exposing uninitialized memory in the case of `read_exact` returning
        // an error.
        unsafe {
            self.temp_buffer.set_len(length);
        }

        Ok(())
    }
}

impl<'a, R> BincodeRead<'a> for IoReader<R>
where
    R: io::Read,
{
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'a>,
    {
        self.fill_buffer(length)?;

        let string = match ::std::str::from_utf8(&self.temp_buffer[..]) {
            Ok(s) => s,
            Err(e) => return Err(::ErrorKind::InvalidUtf8Encoding(e).into()),
        };

        visitor.visit_str(string)
    }

    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        self.fill_buffer(length)?;
        Ok(::std::mem::replace(&mut self.temp_buffer, Vec::new()))
    }

    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'a>,
    {
        self.fill_buffer(length)?;
        visitor.visit_bytes(&self.temp_buffer[..])
    }
}
<commit_msg>Overoptimize slice reader (#308)<commit_after>use error::Result;
use serde;
use std::{io, slice};

/// An optional Read trait for advanced Bincode usage.
///
/// It is highly recommended to use bincode with `io::Read` or `&[u8]` before
/// implementing a custom `BincodeRead`.
///
/// The forward_read_* methods are necessary because some byte sources want
/// to pass a long-lived borrow to the visitor and others want to pass a
/// transient slice.
pub trait BincodeRead<'storage>: io::Read {
    /// Check that the next `length` bytes are a valid string and pass
    /// it on to the serde reader.
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>;

    /// Transfer ownership of the next `length` bytes to the caller.
    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>>;

    /// Pass a slice of the next `length` bytes on to the serde reader.
    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>;
}

/// A BincodeRead implementation for byte slices
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub struct SliceReader<'storage> {
    slice: &'storage [u8],
}

/// A BincodeRead implementation for io::Readers
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub struct IoReader<R> {
    reader: R,
    temp_buffer: Vec<u8>,
}

impl<'storage> SliceReader<'storage> {
    /// Constructs a slice reader
    pub fn new(bytes: &'storage [u8]) -> SliceReader<'storage> {
        SliceReader { slice: bytes }
    }

    #[inline(always)]
    fn get_byte_slice(&mut self, length: usize) -> Result<&'storage [u8]> {
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }
        let (read_slice, remaining) = self.slice.split_at(length);
        self.slice = remaining;
        Ok(read_slice)
    }
}

impl<R> IoReader<R> {
    /// Constructs an IoReadReader
    pub fn new(r: R) -> IoReader<R> {
        IoReader {
            reader: r,
            temp_buffer: vec![],
        }
    }
}

impl<'storage> io::Read for SliceReader<'storage> {
    #[inline(always)]
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        if out.len() > self.slice.len() {
            return Err(io::ErrorKind::UnexpectedEof.into());
        }
        let (read_slice, remaining) = self.slice.split_at(out.len());
        out.copy_from_slice(read_slice);
        self.slice = remaining;

        Ok(out.len())
    }

    #[inline(always)]
    fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> {
        self.read(out).map(|_|())
    }
}

impl<R: io::Read> io::Read for IoReader<R> {
    #[inline(always)]
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        self.reader.read(out)
    }
    #[inline(always)]
    fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> {
        self.reader.read_exact(out)
    }
}

impl<'storage> SliceReader<'storage> {
    #[inline(always)]
    fn unexpected_eof() -> Box<::ErrorKind> {
        return Box::new(::ErrorKind::Io(io::Error::new(
            io::ErrorKind::UnexpectedEof,
            "",
        )));
    }
}

impl<'storage> BincodeRead<'storage> for SliceReader<'storage> {
    #[inline(always)]
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>,
    {
        use ErrorKind;
        let string = match ::std::str::from_utf8(self.get_byte_slice(length)?) {
            Ok(s) => s,
            Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()),
        };
        visitor.visit_borrowed_str(string)
    }

    #[inline(always)]
    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        self.get_byte_slice(length).map(|x| x.to_vec())
    }

    #[inline(always)]
    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>,
    {
        visitor.visit_borrowed_bytes(self.get_byte_slice(length)?)
    }
}

impl<R> IoReader<R>
where
    R: io::Read,
{
    fn fill_buffer(&mut self, length: usize) -> Result<()> {
        // We first reserve the space needed in our buffer.
        let current_length = self.temp_buffer.len();
        if length > current_length {
            self.temp_buffer.reserve_exact(length - current_length);
        }

        // Then create a slice with the length as our desired length. This is
        // safe as long as we only write (no reads) to this buffer, because
        // `reserve_exact` above has allocated this space.
        let buf = unsafe {
            slice::from_raw_parts_mut(self.temp_buffer.as_mut_ptr(), length)
        };

        // This method is assumed to properly handle slices which include
        // uninitialized bytes (as ours does). See discussion at the link below.
        // https://github.com/servo/bincode/issues/260
        self.reader.read_exact(buf)?;

        // Only after `read_exact` successfully returns do we set the buffer
        // length. By doing this after the call to `read_exact`, we can avoid
        // exposing uninitialized memory in the case of `read_exact` returning
        // an error.
        unsafe {
            self.temp_buffer.set_len(length);
        }

        Ok(())
    }
}

impl<'a, R> BincodeRead<'a> for IoReader<R>
where
    R: io::Read,
{
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'a>,
    {
        self.fill_buffer(length)?;

        let string = match ::std::str::from_utf8(&self.temp_buffer[..]) {
            Ok(s) => s,
            Err(e) => return Err(::ErrorKind::InvalidUtf8Encoding(e).into()),
        };

        visitor.visit_str(string)
    }

    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        self.fill_buffer(length)?;
        Ok(::std::mem::replace(&mut self.temp_buffer, Vec::new()))
    }

    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'a>,
    {
        self.fill_buffer(length)?;
        visitor.visit_bytes(&self.temp_buffer[..])
    }
}
<|endoftext|>


<commit_before>extern crate orbclient;

use std::cmp::max;
use std::env;

use orbclient::{BmpFile, Color, EventOption, Window};

fn main() {
    let path = match env::args().nth(1) {
        Some(arg) => arg,
        None => "res/redox.bmp".to_string(),
    };

    let bmp = BmpFile::from_path(&path);
    let mut window = Window::new(-1,
                                 -1,
                                 max(32, bmp.width() as u32),
                                 max(32, bmp.height() as u32),
                                 &path)
                         .unwrap();
    window.set(Color::rgb(0, 0, 0));
    window.image(0, 0, bmp.width() as u32, bmp.height() as u32, &bmp);
    window.sync();

    loop {
        for event in window.events() {
            println!("{:?}", event.to_option());
            if let EventOption::Quit(_) = event.to_option() {
                return;
            }
        }
    }
}
<commit_msg>Move the example to a new directory<commit_after><|endoftext|>


<commit_before>#![feature(core)]

extern crate bootstrap_rs as bootstrap;
extern crate bootstrap_audio as bs_audio;
extern crate parse_collada as collada;
extern crate polygon_rs as polygon;
extern crate polygon_math as math;

pub mod engine;
pub mod scene;
pub mod input;
pub mod resource;
pub mod ecs;
pub mod component;

mod wav;

pub use math::*;
pub use self::engine::Engine;
pub use self::scene::Scene;
pub use self::input::{Input, ScanCode};
pub use self::resource::ResourceManager;
pub use self::ecs::{Entity, EntityManager, System, ComponentManager};
pub use self::component::transform::{TransformManager, Transform};
pub use self::component::camera::{CameraManager, Camera};
pub use self::component::mesh::{MeshManager, Mesh};
pub use self::component::light::{LightManager, Light, PointLight};
pub use self::component::audio::{AudioSourceManager, AudioSource};
pub use self::component::struct_component_manager::StructComponentManager;

pub use self::engine::{engine_init, engine_update_and_render};
<commit_msg>Compile on Linux<commit_after>#![feature(core_intrinsics, raw)]

extern crate bootstrap_rs as bootstrap;
extern crate bootstrap_audio as bs_audio;
extern crate parse_collada as collada;
extern crate polygon_rs as polygon;
extern crate polygon_math as math;

pub mod engine;
pub mod scene;
pub mod input;
pub mod resource;
pub mod ecs;
pub mod component;

mod wav;

pub use math::*;
pub use self::engine::Engine;
pub use self::scene::Scene;
pub use self::input::{Input, ScanCode};
pub use self::resource::ResourceManager;
pub use self::ecs::{Entity, EntityManager, System, ComponentManager};
pub use self::component::transform::{TransformManager, Transform};
pub use self::component::camera::{CameraManager, Camera};
pub use self::component::mesh::{MeshManager, Mesh};
pub use self::component::light::{LightManager, Light, PointLight};
pub use self::component::audio::{AudioSourceManager, AudioSource};
pub use self::component::struct_component_manager::StructComponentManager;

pub use self::engine::{engine_init, engine_update_and_render};
<|endoftext|>


<commit_before>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
use libc;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new() -> History {
        Self::with_config(Config::default())
    }
    pub fn with_config(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    /// TODO append_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30
    /// TODO history_truncate_file http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = if cfg!(unix) {
            unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
        } else {
            0
        };
        let f = File::create(path);
        if cfg!(unix) {
            unsafe {
                libc::umask(old_umask);
            }
        }
        let file = try!(f);
        if cfg!(unix) {
            use std::os::unix::io::AsRawFd;
            unsafe {
                libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
            }
        }
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1]).
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use config::Config;
    use super::{Direction, History};

    fn init() -> History {
        let mut history = History::new();
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let history = History::new();
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::with_config(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<commit_msg>Try to fix windows build<commit_after>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
#[cfg(unix)]
use libc;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new() -> History {
        Self::with_config(Config::default())
    }
    pub fn with_config(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    /// TODO append_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30
    /// TODO history_truncate_file http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = umask();
        let f = File::create(path);
        restore_umask(old_umask);
        let file = try!(f);
        fix_perm(&file);
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1]).
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(windows)]
fn umask() -> u16 {
    0
}
#[cfg(unix)]
fn umask() -> u16 {
    unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
}
#[cfg(windows)]
fn restore_umask(_: u16) {}
#[cfg(unix)]
fn restore_umask(old_umask: u16) {
    unsafe {
        libc::umask(old_umask);
    }
}

#[cfg(windows)]
fn fix_perm(file: &File) {}
#[cfg(unix)]
fn fix_perm(file: &File) {
    use std::os::unix::io::AsRawFd;
    unsafe {
        libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use config::Config;
    use super::{Direction, History};

    fn init() -> History {
        let mut history = History::new();
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let history = History::new();
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::with_config(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<|endoftext|>


<commit_before>// hex encoder and decoder used by rust-protobuf unittests

#![allow(dead_code)]

use std::str;
use std::char;

fn decode_hex_digit(digit: char) -> u8 {
    match char::to_digit(digit, 16) {
        Some(d) => d as u8,
        _ => fail!()
    }
}

pub fn decode_hex(hex: &str) -> Vec<u8> {
    let mut r: Vec<u8> = Vec::new();
    let mut pos = 0;
    loop {
        while pos < hex.char_len() && hex[pos] == ' ' as u8 {
            pos += 1;
        }
        if hex.char_len() - pos >= 2 {
            r.push((decode_hex_digit(hex.char_at(pos)) << 4) | decode_hex_digit(hex.char_at(pos + 1)));
            pos += 2;
            continue;
        }
        if pos == hex.char_len() {
            break;
        }
        fail!("pos = {:u}d", pos);
    }
    r
}

fn encode_hex_digit(digit: u8) -> char {
    match char::from_digit(digit as uint, 16) {
        Some(c) => c,
        _ => fail!()
    }
}

fn encode_hex_byte(byte: u8) -> [char, ..2] {
    [encode_hex_digit(byte >> 4), encode_hex_digit(byte & 0x0Fu8)]
}

pub fn encode_hex(bytes: &[u8]) -> String {
    let strs: Vec<String> = bytes.iter().map(|byte| {
        str::from_chars(encode_hex_byte(*byte).as_slice())
    }).collect();
    strs.connect(" ")
}

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

    #[test]
    fn test_decode_hex() {
        assert_eq!(Vec::from_slice([]), decode_hex(""));
        assert_eq!(Vec::from_slice([0x00u8]), decode_hex("00"));
        assert_eq!(Vec::from_slice([0xffu8]), decode_hex("ff"));
        assert_eq!(Vec::from_slice([0xabu8]), decode_hex("AB"));
        assert_eq!(Vec::from_slice([0xfau8, 0x19]), decode_hex("fa 19"));
    }

    #[test]
    fn test_encode_hex() {
        assert_eq!("".to_string(), encode_hex([]));
        assert_eq!("00".to_string(), encode_hex([0x00]));
        assert_eq!("ab".to_string(), encode_hex([0xab]));
        assert_eq!("01 a2 1a fe".to_string(), encode_hex([0x01, 0xa2, 0x1a, 0xfe]));
    }
}
<commit_msg>Fix compilation<commit_after>// hex encoder and decoder used by rust-protobuf unittests

#![allow(dead_code)]

use std::str;
use std::char;

fn decode_hex_digit(digit: char) -> u8 {
    match char::to_digit(digit, 16) {
        Some(d) => d as u8,
        _ => fail!()
    }
}

pub fn decode_hex(hex: &str) -> Vec<u8> {
    let mut r: Vec<u8> = Vec::new();
    let mut pos = 0;
    loop {
        while pos < hex.char_len() && hex.to_ascii().get(pos).unwrap().to_byte() == ' ' as u8 {
            pos += 1;
        }
        if hex.char_len() - pos >= 2 {
            r.push((decode_hex_digit(hex.char_at(pos)) << 4) | decode_hex_digit(hex.char_at(pos + 1)));
            pos += 2;
            continue;
        }
        if pos == hex.char_len() {
            break;
        }
        fail!("pos = {:u}d", pos);
    }
    r
}

fn encode_hex_digit(digit: u8) -> char {
    match char::from_digit(digit as uint, 16) {
        Some(c) => c,
        _ => fail!()
    }
}

fn encode_hex_byte(byte: u8) -> [char, ..2] {
    [encode_hex_digit(byte >> 4), encode_hex_digit(byte & 0x0Fu8)]
}

pub fn encode_hex(bytes: &[u8]) -> String {
    let strs: Vec<String> = bytes.iter().map(|byte| {
        str::from_chars(encode_hex_byte(*byte).as_slice())
    }).collect();
    strs.connect(" ")
}

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

    #[test]
    fn test_decode_hex() {
        assert_eq!(Vec::from_slice([]), decode_hex(""));
        assert_eq!(Vec::from_slice([0x00u8]), decode_hex("00"));
        assert_eq!(Vec::from_slice([0xffu8]), decode_hex("ff"));
        assert_eq!(Vec::from_slice([0xabu8]), decode_hex("AB"));
        assert_eq!(Vec::from_slice([0xfau8, 0x19]), decode_hex("fa 19"));
    }

    #[test]
    fn test_encode_hex() {
        assert_eq!("".to_string(), encode_hex([]));
        assert_eq!("00".to_string(), encode_hex([0x00]));
        assert_eq!("ab".to_string(), encode_hex([0xab]));
        assert_eq!("01 a2 1a fe".to_string(), encode_hex([0x01, 0xa2, 0x1a, 0xfe]));
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use super::*;

use objc::runtime::{Object, YES, NO};
use objc_foundation::{NSString, INSString, NSArray};
use cocoa::foundation::{NSUInteger};
use foreign_types::ForeignType;
use std::ffi::CStr;

pub enum MTLVertexAttribute {}

foreign_obj_type! {
    type CType = MTLVertexAttribute;
    pub struct VertexAttribute;
    pub struct VertexAttributeRef;
}

impl VertexAttributeRef {
    pub fn name(&self) -> &str {
        unsafe {
            let name: &NSString = msg_send![self, name];
            name.as_str()
        }
    }

    pub fn attribute_index(&self) -> u64 {
        unsafe {
            msg_send![self, attributeIndex]
        }
    }

    pub fn attribute_type(&self) -> MTLDataType {
        unsafe {
            msg_send![self, attributeType]
        }
    }

    pub fn is_active(&self) -> bool {
        unsafe {
            match msg_send![self, isActive] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

}

#[repr(u64)]
#[derive(Debug)]
pub enum MTLFunctionType {
    Vertex = 1,
    Fragment = 2,
    Kernel = 3,
}

pub enum MTLFunction {}

foreign_obj_type! {
    type CType = MTLFunction;
    pub struct Function;
    pub struct FunctionRef;
}

impl FunctionRef {
    pub fn name(&self) -> &str {
        unsafe {
            let name: &NSString = msg_send![self, name];
            name.as_str()
        }
    }

    pub fn function_type(&self) -> MTLFunctionType {
        unsafe {
            msg_send![self, functionType]
        }
    }

    pub fn vertex_attributes(&self) -> &Array<VertexAttribute> {
        unsafe {
            msg_send![self, vertexAttributes]
        }
    }

    pub fn new_argument_encoder(&self, buffer_index: NSUInteger) -> ArgumentEncoder {
        unsafe {
            let ptr = msg_send![self, newArgumentEncoderWithBufferIndex:buffer_index];
            ArgumentEncoder::from_ptr(ptr)
        }
    }

    pub fn function_constants_dictionary(&self) -> *mut Object {
        unsafe {
            msg_send![self, functionConstantsDictionary]
        }
    }
}

#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum MTLLanguageVersion {
    V1_0 = 0x10000,
    V1_1 = 0x10001,
    V1_2 = 0x10002,
    V2_0 = 0x20000,
}

pub enum MTLFunctionConstantValues {}

foreign_obj_type! {
    type CType = MTLFunctionConstantValues;
    pub struct FunctionConstantValues;
    pub struct FunctionConstantValuesRef;
}

impl FunctionConstantValues {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLFunctionConstantValues);
            msg_send![class, new]
        }
    }
}

impl FunctionConstantValuesRef {
    pub unsafe fn set_constant_value_at_index(&self, index: NSUInteger, ty: MTLDataType, value: *const std::os::raw::c_void) {
        msg_send![self, setConstantValue:value type:ty atIndex:index]
    }
}

pub enum MTLCompileOptions {}

foreign_obj_type! {
    type CType = MTLCompileOptions;
    pub struct CompileOptions;
    pub struct CompileOptionsRef;
}

impl CompileOptions {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLCompileOptions);
            msg_send![class, new]
        }
    }
}

impl CompileOptionsRef {
    pub unsafe fn preprocessor_defines(&self) -> *mut Object {
        msg_send![self, preprocessorMacros]
    }

    pub unsafe fn set_preprocessor_defines(&self, defines: *mut Object) {
        msg_send![self, setPreprocessorMacros:defines]
    }

    pub fn is_fast_math_enabled(&self) -> bool {
        unsafe {
            match msg_send![self, fastMathEnabled] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn set_fast_math_enabled(&self, enabled: bool) {
        unsafe {
            msg_send![self, setFastMathEnabled:enabled]
        }
    }

    pub fn language_version(&self) -> MTLLanguageVersion {
        unsafe {
            msg_send![self, languageVersion]
        }
    }

    pub fn set_language_version(&self, version: MTLLanguageVersion) {
        unsafe {
            msg_send![self, setLanguageVersion:version]
        }
    }
}

#[repr(u64)]
#[allow(non_camel_case_types)]
pub enum MTLLibraryError {
    Unsupported      = 1,
    Internal         = 2,
    CompileFailure   = 3,
    CompileWarning   = 4,
}

pub enum MTLLibrary {}

foreign_obj_type! {
    type CType = MTLLibrary;
    pub struct Library;
    pub struct LibraryRef;
}

impl LibraryRef {
    pub fn label(&self) -> &str {
        unsafe {
            let label: &NSString = msg_send![self, label];
            label.as_str()
        }
    }

    pub fn set_label(&self, label: &str) {
        unsafe {
            let nslabel = NSString::from_str(label);
            msg_send![self, setLabel:nslabel]
        }
    }

    pub fn get_function(&self, name: &str, constants: Option<FunctionConstantValues>) -> Result<Function, String> {
        unsafe {
            use cocoa::foundation::NSString as cocoa_NSString;
            use cocoa::base::nil as cocoa_nil;

            let nsname = cocoa_NSString::alloc(cocoa_nil).init_str(name);

            let function: *mut MTLFunction = match constants {
                Some(c) => try_objc!{ err => msg_send![self, newFunctionWithName:nsname constantValues:c error:&mut err] },
                None => msg_send![self, newFunctionWithName:nsname]
            };

            if !function.is_null() {
                Ok(Function::from_ptr(function))
            } else {
                Err(format!("Function '{}' does not exist", name))
            }
        }
    }

    pub fn function_names(&self) -> &NSArray<NSString> {
        unsafe {
            msg_send![self, functionNames]
        }
    }
}
<commit_msg>add MTLLanguageVersion 2.1<commit_after>// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use super::*;

use objc::runtime::{Object, YES, NO};
use objc_foundation::{NSString, INSString, NSArray};
use cocoa::foundation::{NSUInteger};
use foreign_types::ForeignType;
use std::ffi::CStr;

pub enum MTLVertexAttribute {}

foreign_obj_type! {
    type CType = MTLVertexAttribute;
    pub struct VertexAttribute;
    pub struct VertexAttributeRef;
}

impl VertexAttributeRef {
    pub fn name(&self) -> &str {
        unsafe {
            let name: &NSString = msg_send![self, name];
            name.as_str()
        }
    }

    pub fn attribute_index(&self) -> u64 {
        unsafe {
            msg_send![self, attributeIndex]
        }
    }

    pub fn attribute_type(&self) -> MTLDataType {
        unsafe {
            msg_send![self, attributeType]
        }
    }

    pub fn is_active(&self) -> bool {
        unsafe {
            match msg_send![self, isActive] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

}

#[repr(u64)]
#[derive(Debug)]
pub enum MTLFunctionType {
    Vertex = 1,
    Fragment = 2,
    Kernel = 3,
}

pub enum MTLFunction {}

foreign_obj_type! {
    type CType = MTLFunction;
    pub struct Function;
    pub struct FunctionRef;
}

impl FunctionRef {
    pub fn name(&self) -> &str {
        unsafe {
            let name: &NSString = msg_send![self, name];
            name.as_str()
        }
    }

    pub fn function_type(&self) -> MTLFunctionType {
        unsafe {
            msg_send![self, functionType]
        }
    }

    pub fn vertex_attributes(&self) -> &Array<VertexAttribute> {
        unsafe {
            msg_send![self, vertexAttributes]
        }
    }

    pub fn new_argument_encoder(&self, buffer_index: NSUInteger) -> ArgumentEncoder {
        unsafe {
            let ptr = msg_send![self, newArgumentEncoderWithBufferIndex:buffer_index];
            ArgumentEncoder::from_ptr(ptr)
        }
    }

    pub fn function_constants_dictionary(&self) -> *mut Object {
        unsafe {
            msg_send![self, functionConstantsDictionary]
        }
    }
}

#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum MTLLanguageVersion {
    V1_0 = 0x10000,
    V1_1 = 0x10001,
    V1_2 = 0x10002,
    V2_0 = 0x20000,
    V2_1 = 0x20001,
}

pub enum MTLFunctionConstantValues {}

foreign_obj_type! {
    type CType = MTLFunctionConstantValues;
    pub struct FunctionConstantValues;
    pub struct FunctionConstantValuesRef;
}

impl FunctionConstantValues {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLFunctionConstantValues);
            msg_send![class, new]
        }
    }
}

impl FunctionConstantValuesRef {
    pub unsafe fn set_constant_value_at_index(&self, index: NSUInteger, ty: MTLDataType, value: *const std::os::raw::c_void) {
        msg_send![self, setConstantValue:value type:ty atIndex:index]
    }
}

pub enum MTLCompileOptions {}

foreign_obj_type! {
    type CType = MTLCompileOptions;
    pub struct CompileOptions;
    pub struct CompileOptionsRef;
}

impl CompileOptions {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLCompileOptions);
            msg_send![class, new]
        }
    }
}

impl CompileOptionsRef {
    pub unsafe fn preprocessor_defines(&self) -> *mut Object {
        msg_send![self, preprocessorMacros]
    }

    pub unsafe fn set_preprocessor_defines(&self, defines: *mut Object) {
        msg_send![self, setPreprocessorMacros:defines]
    }

    pub fn is_fast_math_enabled(&self) -> bool {
        unsafe {
            match msg_send![self, fastMathEnabled] {
                YES => true,
                NO => false,
                _ => unreachable!()
            }
        }
    }

    pub fn set_fast_math_enabled(&self, enabled: bool) {
        unsafe {
            msg_send![self, setFastMathEnabled:enabled]
        }
    }

    pub fn language_version(&self) -> MTLLanguageVersion {
        unsafe {
            msg_send![self, languageVersion]
        }
    }

    pub fn set_language_version(&self, version: MTLLanguageVersion) {
        unsafe {
            msg_send![self, setLanguageVersion:version]
        }
    }
}

#[repr(u64)]
#[allow(non_camel_case_types)]
pub enum MTLLibraryError {
    Unsupported      = 1,
    Internal         = 2,
    CompileFailure   = 3,
    CompileWarning   = 4,
}

pub enum MTLLibrary {}

foreign_obj_type! {
    type CType = MTLLibrary;
    pub struct Library;
    pub struct LibraryRef;
}

impl LibraryRef {
    pub fn label(&self) -> &str {
        unsafe {
            let label: &NSString = msg_send![self, label];
            label.as_str()
        }
    }

    pub fn set_label(&self, label: &str) {
        unsafe {
            let nslabel = NSString::from_str(label);
            msg_send![self, setLabel:nslabel]
        }
    }

    pub fn get_function(&self, name: &str, constants: Option<FunctionConstantValues>) -> Result<Function, String> {
        unsafe {
            use cocoa::foundation::NSString as cocoa_NSString;
            use cocoa::base::nil as cocoa_nil;

            let nsname = cocoa_NSString::alloc(cocoa_nil).init_str(name);

            let function: *mut MTLFunction = match constants {
                Some(c) => try_objc!{ err => msg_send![self, newFunctionWithName:nsname constantValues:c error:&mut err] },
                None => msg_send![self, newFunctionWithName:nsname]
            };

            if !function.is_null() {
                Ok(Function::from_ptr(function))
            } else {
                Err(format!("Function '{}' does not exist", name))
            }
        }
    }

    pub fn function_names(&self) -> &NSArray<NSString> {
        unsafe {
            msg_send![self, functionNames]
        }
    }
}
<|endoftext|>


<commit_before>pub mod gen;
pub mod dump;

use std::cell::RefCell;
use std::rc::Rc;
use std::slice::{Iter, IterMut};
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use ast::{BinOp, UnOp};
use interner::Name;
use sym::BuiltinType;

pub struct Fct {
    blocks: Vec<Rc<RefCell<Block>>>,
    start_id: BlockId,
    end_ids: Vec<BlockId>,
    vars: Vec<Var>,
    params: Vec<Var>,
}

impl Debug for Fct {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "fct")
    }
}

impl Fct {
    pub fn new() -> Fct {
        Fct {
            blocks: Vec::new(),
            start_id: BlockId(0),
            end_ids: Vec::new(),
            vars: Vec::new(),
            params: Vec::new(),
        }
    }

    pub fn block(&self, id: BlockId) -> Rc<RefCell<Block>> {
        self.blocks[id.0].clone()
    }

    pub fn increase_var(&mut self, id: VarId) -> u32 {
        let var = self.var_mut(id);
        var.next_ssa += 1;

        var.next_ssa
    }

    pub fn var_mut(&mut self, id: VarId) -> &mut Var {
        &mut self.vars[id.0]
    }

    pub fn var(&self, id: VarId) -> &Var {
        &self.vars[id.0]
    }

    pub fn add_block(&mut self) -> BlockId {
        let id = BlockId(self.blocks.len());
        self.blocks.push(Rc::new(RefCell::new(Block::new(id))));

        id
    }

    pub fn add_var(&mut self, name: Name, data_type: BuiltinType) -> VarId {
        let id = VarId(self.vars.len());
        self.vars.push(Var {
            id: id,
            name: name,
            data_type: data_type,
            cur_ssa: 0,
            next_ssa: 0
        });

        id
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct VarId(usize);

impl ToString for VarId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct Var {
    id: VarId,
    name: Name,
    data_type: BuiltinType,
    cur_ssa: u32,
    next_ssa: u32,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct BlockId(usize);

impl ToString for BlockId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct Block {
    id: BlockId,
    instructions: Vec<Instr>,
    predecessors: Vec<BlockId>,
}

impl Block {
    fn new(id: BlockId) -> Block {
        Block {
            id: id,
            instructions: Vec::new(),
            predecessors: Vec::new()
        }
    }

    fn add_instr(&mut self, instr: Instr) {
        self.instructions.push(instr);
    }

    fn last_instr(&self) -> Option<&Instr> {
        self.instructions.last()
    }

    fn add_predecessor(&mut self, id: BlockId) {
        self.predecessors.push(id);
    }

    fn find_phi_mut(&mut self, id: VarId) -> Option<&mut InstrPhiType> {
        for instr in &mut self.instructions {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                if phi.var_id == id {
                    return Some(phi);
                }

            } else {
                return None;
            }
        }

        None
    }

    fn add_phi(&mut self, phi: InstrPhiType) {
        let mut ind : usize = 0;

        for instr in &self.instructions {
            if let Instr::InstrPhi(ref instr_phi) = *instr {
                if instr_phi.var_id == phi.var_id {
                    panic!("phi-instruction for var {} already exists.",
                        phi.var_id.to_string());
                }

                ind += 1;
            } else {
                break;
            }
        }

        self.instructions.insert(ind, Instr::InstrPhi(phi));
    }

    fn phi_iter(&self) -> PhiIter {
        PhiIter {
            iter: self.instructions.iter()
        }
    }

    fn phi_iter_mut(&mut self) -> PhiIterMut {
        PhiIterMut {
            iter: self.instructions.iter_mut()
        }
    }
}

struct PhiIter<'a> {
    iter: Iter<'a, Instr>
}

impl<'a> Iterator for PhiIter<'a> {
    type Item = &'a InstrPhiType;

    fn next(&mut self) -> Option<&'a InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct PhiIterMut<'a> {
    iter: IterMut<'a, Instr>
}

impl<'a> Iterator for PhiIterMut<'a> {
    type Item = &'a mut InstrPhiType;

    fn next(&mut self) -> Option<&'a mut InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Instr {
    InstrRet(Option<Opnd>),
    InstrTest(InstrTestType),
    InstrBin(InstrBinType),
    InstrUn(InstrUnType),
    InstrAssign(InstrAssignType),
    InstrPhi(InstrPhiType),
    InstrCall(InstrCallType),
    InstrStr(InstrStrType),
    InstrGoto(BlockId),
}

impl Instr {
    fn ret() -> Instr {
        Instr::InstrRet(None)
    }

    fn ret_value(opnd: Opnd) -> Instr {
        Instr::InstrRet(Some(opnd))
    }

    fn test(opnd: Opnd, true_block: BlockId, false_block: BlockId) -> Instr {
        Instr::InstrTest(InstrTestType {
            opnd: opnd,
            true_block: true_block,
            false_block: false_block,
        })
    }

    fn bin(dest: Opnd, lhs: Opnd, op: BinOp, rhs: Opnd) -> Instr {
        Instr::InstrBin(InstrBinType {
            dest: dest,
            lhs: lhs,
            op: op,
            rhs: rhs,
        })
    }

    fn un(dest: Opnd, op: UnOp, src: Opnd) -> Instr {
        Instr::InstrUn(InstrUnType {
            dest: dest,
            op: op,
            src: src,
        })
    }

    fn assign(dest: Opnd, src: Opnd) -> Instr {
        Instr::InstrAssign(InstrAssignType {
            dest: dest,
            src: src,
        })
    }

    fn call(dest: Opnd, name: String, args: Vec<Opnd>) -> Instr {
        Instr::InstrCall(InstrCallType {
            dest: dest,
            name: name,
            args: args,
        })
    }

    fn str(dest: Opnd, value: String) -> Instr {
        Instr::InstrStr(InstrStrType {
            dest: dest,
            value: value,
        })
    }

    fn goto(target: BlockId) -> Instr {
        Instr::InstrGoto(target)
    }

    fn phi(var_id: VarId, dest: u32, opnds: Vec<u32>, backup: u32) -> Instr {
        Instr::InstrPhi(InstrPhiType {
            var_id: var_id,
            dest: dest,
            opnds: opnds,
            backup: backup,
        })
    }
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrTestType {
    pub opnd: Opnd,
    pub true_block: BlockId,
    pub false_block: BlockId,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrBinType {
    pub dest: Opnd,
    pub lhs: Opnd,
    pub op: BinOp,
    pub rhs: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrUnType {
    pub dest: Opnd,
    pub op: UnOp,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrAssignType {
    pub dest: Opnd,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrCallType {
    pub dest: Opnd,
    pub name: String,
    pub args: Vec<Opnd>,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrPhiType {
    pub var_id: VarId,
    pub dest: u32,
    pub opnds: Vec<u32>,
    pub backup: u32,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrStrType {
    pub dest: Opnd,
    pub value: String,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Opnd {
    OpndReg(u32),
    OpndVar(VarId, u32),
    OpndInt(i32),
    OpndBool(bool),
}

#[cfg(test)]
mod tests {
    use interner::Name;
    use mir::*;
    use mir::Instr::*;
    use sym::BuiltinType;

    #[test]
    fn find_phi_fails() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.find_phi_mut(VarId(0)));
    }

    #[test]
    fn find_phi_succeeds() {
        let mut block = Block::new(BlockId(0));
        let phi = Instr::phi(VarId(0), 0, Vec::new(), 0);
        block.add_instr(phi);

        assert!(block.find_phi_mut(VarId(0)).is_some());
        assert_eq!(None, block.find_phi_mut(VarId(1)));
    }

    #[test]
    fn increase_var() {
        let mut fct = Fct::new();
        let var_id = fct.add_var(Name(0), BuiltinType::Int);

        assert_eq!(1, fct.increase_var(var_id));
    }

    #[test]
    #[should_panic]
    fn add_phi_panics() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(0));
        block.add_phi(phi(0));
    }

    #[test]
    fn add_phi() {
        let mut block = Block::new(BlockId(0));

        block.add_instr(Instr::ret());
        block.add_phi(phi(0));
        block.add_phi(phi(1));
        block.add_phi(phi(2));

        let instrs = &block.instructions;

        assert_eq!(phi_instr(0), instrs[0]);
        assert_eq!(phi_instr(1), instrs[1]);
        assert_eq!(phi_instr(2), instrs[2]);
        assert_eq!(Instr::ret(), instrs[3]);
    }

    #[test]
    fn phi_iterator_empty() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.phi_iter().next());
    }

    #[test]
    fn phi_iterator_single() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(3));
        block.add_instr(Instr::ret());

        let mut iter = block.phi_iter();
        assert_eq!(Some(&phi(3)), iter.next());
        assert_eq!(None, iter.next());
    }

    fn phi_instr(var: usize) -> Instr {
        InstrPhi(phi(var))
    }

    fn phi(var: usize) -> InstrPhiType {
        InstrPhiType {
            var_id: VarId(var),
            dest: 0,
            opnds: Vec::new(),
            backup: 0
        }
    }
}
<commit_msg>MIR: removed params from Fct<commit_after>pub mod gen;
pub mod dump;

use std::cell::RefCell;
use std::rc::Rc;
use std::slice::{Iter, IterMut};
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use ast::{BinOp, UnOp};
use interner::Name;
use sym::BuiltinType;

pub struct Fct {
    blocks: Vec<Rc<RefCell<Block>>>,
    start_id: BlockId,
    end_ids: Vec<BlockId>,
    vars: Vec<Var>,
}

impl Debug for Fct {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "fct")
    }
}

impl Fct {
    pub fn new() -> Fct {
        Fct {
            blocks: Vec::new(),
            start_id: BlockId(0),
            end_ids: Vec::new(),
            vars: Vec::new(),
        }
    }

    pub fn block(&self, id: BlockId) -> Rc<RefCell<Block>> {
        self.blocks[id.0].clone()
    }

    pub fn increase_var(&mut self, id: VarId) -> u32 {
        let var = self.var_mut(id);
        var.next_ssa += 1;

        var.next_ssa
    }

    pub fn var_mut(&mut self, id: VarId) -> &mut Var {
        &mut self.vars[id.0]
    }

    pub fn var(&self, id: VarId) -> &Var {
        &self.vars[id.0]
    }

    pub fn add_block(&mut self) -> BlockId {
        let id = BlockId(self.blocks.len());
        self.blocks.push(Rc::new(RefCell::new(Block::new(id))));

        id
    }

    pub fn add_var(&mut self, name: Name, data_type: BuiltinType) -> VarId {
        let id = VarId(self.vars.len());
        self.vars.push(Var {
            id: id,
            name: name,
            data_type: data_type,
            cur_ssa: 0,
            next_ssa: 0
        });

        id
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct VarId(usize);

impl ToString for VarId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct Var {
    id: VarId,
    name: Name,
    data_type: BuiltinType,
    cur_ssa: u32,
    next_ssa: u32,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct BlockId(usize);

impl ToString for BlockId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct Block {
    id: BlockId,
    instructions: Vec<Instr>,
    predecessors: Vec<BlockId>,
}

impl Block {
    fn new(id: BlockId) -> Block {
        Block {
            id: id,
            instructions: Vec::new(),
            predecessors: Vec::new()
        }
    }

    fn add_instr(&mut self, instr: Instr) {
        self.instructions.push(instr);
    }

    fn last_instr(&self) -> Option<&Instr> {
        self.instructions.last()
    }

    fn add_predecessor(&mut self, id: BlockId) {
        self.predecessors.push(id);
    }

    fn find_phi_mut(&mut self, id: VarId) -> Option<&mut InstrPhiType> {
        for instr in &mut self.instructions {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                if phi.var_id == id {
                    return Some(phi);
                }

            } else {
                return None;
            }
        }

        None
    }

    fn add_phi(&mut self, phi: InstrPhiType) {
        let mut ind : usize = 0;

        for instr in &self.instructions {
            if let Instr::InstrPhi(ref instr_phi) = *instr {
                if instr_phi.var_id == phi.var_id {
                    panic!("phi-instruction for var {} already exists.",
                        phi.var_id.to_string());
                }

                ind += 1;
            } else {
                break;
            }
        }

        self.instructions.insert(ind, Instr::InstrPhi(phi));
    }

    fn phi_iter(&self) -> PhiIter {
        PhiIter {
            iter: self.instructions.iter()
        }
    }

    fn phi_iter_mut(&mut self) -> PhiIterMut {
        PhiIterMut {
            iter: self.instructions.iter_mut()
        }
    }
}

struct PhiIter<'a> {
    iter: Iter<'a, Instr>
}

impl<'a> Iterator for PhiIter<'a> {
    type Item = &'a InstrPhiType;

    fn next(&mut self) -> Option<&'a InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct PhiIterMut<'a> {
    iter: IterMut<'a, Instr>
}

impl<'a> Iterator for PhiIterMut<'a> {
    type Item = &'a mut InstrPhiType;

    fn next(&mut self) -> Option<&'a mut InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Instr {
    InstrRet(Option<Opnd>),
    InstrTest(InstrTestType),
    InstrBin(InstrBinType),
    InstrUn(InstrUnType),
    InstrAssign(InstrAssignType),
    InstrPhi(InstrPhiType),
    InstrCall(InstrCallType),
    InstrStr(InstrStrType),
    InstrGoto(BlockId),
}

impl Instr {
    fn ret() -> Instr {
        Instr::InstrRet(None)
    }

    fn ret_value(opnd: Opnd) -> Instr {
        Instr::InstrRet(Some(opnd))
    }

    fn test(opnd: Opnd, true_block: BlockId, false_block: BlockId) -> Instr {
        Instr::InstrTest(InstrTestType {
            opnd: opnd,
            true_block: true_block,
            false_block: false_block,
        })
    }

    fn bin(dest: Opnd, lhs: Opnd, op: BinOp, rhs: Opnd) -> Instr {
        Instr::InstrBin(InstrBinType {
            dest: dest,
            lhs: lhs,
            op: op,
            rhs: rhs,
        })
    }

    fn un(dest: Opnd, op: UnOp, src: Opnd) -> Instr {
        Instr::InstrUn(InstrUnType {
            dest: dest,
            op: op,
            src: src,
        })
    }

    fn assign(dest: Opnd, src: Opnd) -> Instr {
        Instr::InstrAssign(InstrAssignType {
            dest: dest,
            src: src,
        })
    }

    fn call(dest: Opnd, name: String, args: Vec<Opnd>) -> Instr {
        Instr::InstrCall(InstrCallType {
            dest: dest,
            name: name,
            args: args,
        })
    }

    fn str(dest: Opnd, value: String) -> Instr {
        Instr::InstrStr(InstrStrType {
            dest: dest,
            value: value,
        })
    }

    fn goto(target: BlockId) -> Instr {
        Instr::InstrGoto(target)
    }

    fn phi(var_id: VarId, dest: u32, opnds: Vec<u32>, backup: u32) -> Instr {
        Instr::InstrPhi(InstrPhiType {
            var_id: var_id,
            dest: dest,
            opnds: opnds,
            backup: backup,
        })
    }
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrTestType {
    pub opnd: Opnd,
    pub true_block: BlockId,
    pub false_block: BlockId,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrBinType {
    pub dest: Opnd,
    pub lhs: Opnd,
    pub op: BinOp,
    pub rhs: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrUnType {
    pub dest: Opnd,
    pub op: UnOp,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrAssignType {
    pub dest: Opnd,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrCallType {
    pub dest: Opnd,
    pub name: String,
    pub args: Vec<Opnd>,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrPhiType {
    pub var_id: VarId,
    pub dest: u32,
    pub opnds: Vec<u32>,
    pub backup: u32,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrStrType {
    pub dest: Opnd,
    pub value: String,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Opnd {
    OpndReg(u32),
    OpndVar(VarId, u32),
    OpndInt(i32),
    OpndBool(bool),
}

#[cfg(test)]
mod tests {
    use interner::Name;
    use mir::*;
    use mir::Instr::*;
    use sym::BuiltinType;

    #[test]
    fn find_phi_fails() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.find_phi_mut(VarId(0)));
    }

    #[test]
    fn find_phi_succeeds() {
        let mut block = Block::new(BlockId(0));
        let phi = Instr::phi(VarId(0), 0, Vec::new(), 0);
        block.add_instr(phi);

        assert!(block.find_phi_mut(VarId(0)).is_some());
        assert_eq!(None, block.find_phi_mut(VarId(1)));
    }

    #[test]
    fn increase_var() {
        let mut fct = Fct::new();
        let var_id = fct.add_var(Name(0), BuiltinType::Int);

        assert_eq!(1, fct.increase_var(var_id));
    }

    #[test]
    #[should_panic]
    fn add_phi_panics() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(0));
        block.add_phi(phi(0));
    }

    #[test]
    fn add_phi() {
        let mut block = Block::new(BlockId(0));

        block.add_instr(Instr::ret());
        block.add_phi(phi(0));
        block.add_phi(phi(1));
        block.add_phi(phi(2));

        let instrs = &block.instructions;

        assert_eq!(phi_instr(0), instrs[0]);
        assert_eq!(phi_instr(1), instrs[1]);
        assert_eq!(phi_instr(2), instrs[2]);
        assert_eq!(Instr::ret(), instrs[3]);
    }

    #[test]
    fn phi_iterator_empty() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.phi_iter().next());
    }

    #[test]
    fn phi_iterator_single() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(3));
        block.add_instr(Instr::ret());

        let mut iter = block.phi_iter();
        assert_eq!(Some(&phi(3)), iter.next());
        assert_eq!(None, iter.next());
    }

    fn phi_instr(var: usize) -> Instr {
        InstrPhi(phi(var))
    }

    fn phi(var: usize) -> InstrPhiType {
        InstrPhiType {
            var_id: VarId(var),
            dest: 0,
            opnds: Vec::new(),
            backup: 0
        }
    }
}
<|endoftext|>