<commit_before>// Copyright (c) 2016 The Rouille developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Apply content encodings (such as gzip compression) to the response.
//!
//! This module provides access to the content encodings supported by a request as well as
//! a function to automatically apply common content encodings to a response.
//! # Basic example
//!
//! Here is a basic example showing how to use content encodings:
//!
//! ```
//! use rouille::Request;
//! use rouille::Response;
//! use rouille::content_encoding;
//!
//! fn handle_request(request: &Request) -> Response {
//!     let mut text = String::new();
//!     for encoding in content_encoding::accepted_content_encodings(request) {
//!         text.push_str(encoding);
//!         text.push('\n');
//!     }
//!     let response = Response::text(&text);
//!     content_encoding::apply(&request, response)
//! }
//! ```
use std::str;
use Request;
use Response;

/// Applies content encoding to the response.
///
/// Analyzes the `Accept-Encoding` header of the request. If one of the encodings is recognized and
/// supported by rouille, it adds a `Content-Encoding` header to the `Response` and encodes its
/// body.
///
/// If the response already has a `Content-Encoding` header, this function is a no-op.
/// If the response has a `Content-Type` header that isn't textual content, this function is a
/// no-op.
///
/// The gzip encoding is supported only if you enable the `gzip` feature of rouille (which is
/// enabled by default).
///
/// # Example
///
/// ```rust
/// use rouille::content_encoding;
/// use rouille::Request;
/// use rouille::Response;
///
/// fn handle(request: &Request) -> Response {
///     content_encoding::apply(request, Response::text("hello world"))
/// }
/// ```
pub fn apply(request: &Request, response: Response) -> Response {
    // Only text should be encoded. Otherwise just return.
    if !response_is_text(&response) {
        return response;
    }

    // If any of the response's headers is equal to `Content-Encoding`, ignore the function
    // call and return immediately.
    if response
        .headers
        .iter()
        .any(|&(ref key, _)| key.eq_ignore_ascii_case("Content-Encoding"))
    {
        return response;
    }

    // Put the response in an Option for later.
    let mut response = Some(response);

    // Now let's get the list of content encodings accepted by the request.
    // The list should be ordered from the most desired to the list desired.
    // TODO: use input::priority_header_preferred instead
    for encoding in accepted_content_encodings(request) {
        // Try the brotli encoding.
        if brotli(encoding, &mut response) {
            return response.take().unwrap();
        }

        // Try the gzip encoding.
        if gzip(encoding, &mut response) {
            return response.take().unwrap();
        }

        // The identity encoding is always supported.
        if encoding.eq_ignore_ascii_case("identity") {
            return response.take().unwrap();
        }
    }

    // No encoding accepted, don't do anything.
    response.take().unwrap()
}

// Returns true if the Content-Type of the response is a type that should be encoded.
// Since encoding is purely an optimization, it's not a problem if the function sometimes has
// false positives or false negatives.
fn response_is_text(response: &Response) -> bool {
    response.headers.iter().any(|&(ref key, ref value)| {
        if !key.eq_ignore_ascii_case("Content-Type") {
            return false;
        }

        let content_type = value.to_lowercase();
        content_type.starts_with("text/")
            || content_type.contains("javascript")
            || content_type.contains("json")
            || content_type.contains("xml")
            || content_type.contains("font")
    })
}

/// Returns an iterator of the list of content encodings accepted by the request.
///
/// # Example
///
/// ```
/// use rouille::{Request, Response};
/// use rouille::content_encoding;
///
/// fn handle(request: &Request) -> Response {
///     for encoding in content_encoding::accepted_content_encodings(request) {
///         // ...
///     }
///
///     // ...
/// # panic!()
/// }
/// ```
pub fn accepted_content_encodings(request: &Request) -> AcceptedContentEncodingsIter {
    let elems = request.header("Accept-Encoding").unwrap_or("").split(',');
    AcceptedContentEncodingsIter { elements: elems }
}

/// Iterator to the list of content encodings accepted by a request.
pub struct AcceptedContentEncodingsIter<'a> {
    elements: str::Split<'a, char>,
}

impl<'a> Iterator for AcceptedContentEncodingsIter<'a> {
    type Item = &'a str;

    #[inline]
    fn next(&mut self) -> Option<&'a str> {
        loop {
            match self.elements.next() {
                None => return None,
                Some(e) => {
                    let e = e.trim();
                    if !e.is_empty() {
                        return Some(e);
                    }
                }
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, max) = self.elements.size_hint();
        (0, max)
    }
}

#[cfg(feature = "gzip")]
fn gzip(e: &str, response: &mut Option<Response>) -> bool {
    use deflate::deflate_bytes_gzip;
    use std::io;
    use std::mem;
    use ResponseBody;

    if !e.eq_ignore_ascii_case("gzip") {
        return false;
    }

    let response = response.as_mut().unwrap();
    response
        .headers
        .push(("Content-Encoding".into(), "gzip".into()));
    let previous_body = mem::replace(&mut response.data, ResponseBody::empty());
    let (mut raw_data, size) = previous_body.into_reader_and_size();
    let mut src = match size {
        Some(size) => Vec::with_capacity(size),
        None => Vec::new(),
    };
    io::copy(&mut raw_data, &mut src).expect("Failed reading response body while gzipping");
    let zipped = deflate_bytes_gzip(&src);
    response.data = ResponseBody::from_data(zipped);
    true
}

#[cfg(not(feature = "gzip"))]
#[inline]
fn gzip(e: &str, response: &mut Option<Response>) -> bool {
    false
}

#[cfg(feature = "brotli")]
fn brotli(e: &str, response: &mut Option<Response>) -> bool {
    use brotli2::read::BrotliEncoder;
    use std::mem;
    use ResponseBody;

    if !e.eq_ignore_ascii_case("br") {
        return false;
    }

    let response = response.as_mut().unwrap();
    response
        .headers
        .push(("Content-Encoding".into(), "br".into()));
    let previous_body = mem::replace(&mut response.data, ResponseBody::empty());
    let (raw_data, _) = previous_body.into_reader_and_size();
    response.data = ResponseBody::from_reader(BrotliEncoder::new(raw_data, 6));
    true
}

#[cfg(not(feature = "brotli"))]
#[inline]
fn brotli(e: &str, response: &mut Option<Response>) -> bool {
    false
}

#[cfg(test)]
mod tests {
    use content_encoding;
    use Request;

    #[test]
    fn no_req_encodings() {
        let request = Request::fake_http("GET", "/", vec![], vec![]);
        assert_eq!(
            content_encoding::accepted_content_encodings(&request).count(),
            0
        );
    }

    #[test]
    fn empty_req_encodings() {
        let request = {
            let h = vec![("Accept-Encoding".to_owned(), "".to_owned())];
            Request::fake_http("GET", "/", h, vec![])
        };

        assert_eq!(
            content_encoding::accepted_content_encodings(&request).count(),
            0
        );
    }

    #[test]
    fn one_req_encoding() {
        let request = {
            let h = vec![("Accept-Encoding".to_owned(), "foo".to_owned())];
            Request::fake_http("GET", "/", h, vec![])
        };

        let mut list = content_encoding::accepted_content_encodings(&request);
        assert_eq!(list.next().unwrap(), "foo");
        assert_eq!(list.next(), None);
    }

    #[test]
    fn multi_req_encoding() {
        let request = {
            let h = vec![("Accept-Encoding".to_owned(), "foo, bar".to_owned())];
            Request::fake_http("GET", "/", h, vec![])
        };

        let mut list = content_encoding::accepted_content_encodings(&request);
        assert_eq!(list.next().unwrap(), "foo");
        assert_eq!(list.next().unwrap(), "bar");
        assert_eq!(list.next(), None);
    }

    // TODO: more tests for encoding stuff
}
<commit_msg>Fix TODO: use input::priority_header_preferred() in content_encoding::apply()<commit_after>// Copyright (c) 2016 The Rouille developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Apply content encodings (such as gzip compression) to the response.
//!
//! This module provides access to the content encodings supported by a request as well as
//! a function to automatically apply common content encodings to a response.
//! # Basic example
//!
//! Here is a basic example showing how to use content encodings:
//!
//! ```
//! use rouille::Request;
//! use rouille::Response;
//! use rouille::content_encoding;
//!
//! fn handle_request(request: &Request) -> Response {
//!     let response = Response::text("Hello world");
//!     content_encoding::apply(&request, response)
//! }
//! ```
use input;
use std::str;
use Request;
use Response;

/// Applies content encoding to the response.
///
/// Analyzes the `Accept-Encoding` header of the request. If one of the encodings is recognized and
/// supported by rouille, it adds a `Content-Encoding` header to the `Response` and encodes its
/// body.
///
/// If the response already has a `Content-Encoding` header, this function is a no-op.
/// If the response has a `Content-Type` header that isn't textual content, this function is a
/// no-op.
///
/// The gzip encoding is supported only if you enable the `gzip` feature of rouille (which is
/// enabled by default).
///
/// # Example
///
/// ```rust
/// use rouille::content_encoding;
/// use rouille::Request;
/// use rouille::Response;
///
/// fn handle(request: &Request) -> Response {
///     content_encoding::apply(request, Response::text("hello world"))
/// }
/// ```
pub fn apply(request: &Request, mut response: Response) -> Response {
    // Only text should be encoded. Otherwise just return.
    if !response_is_text(&response) {
        return response;
    }

    // If any of the response's headers is equal to `Content-Encoding`, ignore the function
    // call and return immediately.
    if response
        .headers
        .iter()
        .any(|&(ref key, _)| key.eq_ignore_ascii_case("Content-Encoding"))
    {
        return response;
    }

    // Now let's get the list of content encodings accepted by the request.
    // The list should be ordered from the most desired to the least desired.
    let encoding_preference = ["br", "gzip", "x-gzip", "identity"];
    let accept_encoding_header = request.header("Accept-Encoding").unwrap_or("");
    if let Some(preferred_index) = input::priority_header_preferred(
        &accept_encoding_header,
        encoding_preference.iter().cloned(),
    ) {
        match encoding_preference[preferred_index] {
            "br" => brotli(&mut response),
            "gzip" | "x-gzip" => gzip(&mut response),
            _ => (),
        }
    }

    return response;
}

// Returns true if the Content-Type of the response is a type that should be encoded.
// Since encoding is purely an optimization, it's not a problem if the function sometimes has
// false positives or false negatives.
fn response_is_text(response: &Response) -> bool {
    response.headers.iter().any(|&(ref key, ref value)| {
        if !key.eq_ignore_ascii_case("Content-Type") {
            return false;
        }

        let content_type = value.to_lowercase();
        content_type.starts_with("text/")
            || content_type.contains("javascript")
            || content_type.contains("json")
            || content_type.contains("xml")
            || content_type.contains("font")
    })
}

#[cfg(feature = "gzip")]
fn gzip(response: &mut Response) {
    use deflate::deflate_bytes_gzip;
    use std::io;
    use std::mem;
    use ResponseBody;

    response
        .headers
        .push(("Content-Encoding".into(), "gzip".into()));
    let previous_body = mem::replace(&mut response.data, ResponseBody::empty());
    let (mut raw_data, size) = previous_body.into_reader_and_size();
    let mut src = match size {
        Some(size) => Vec::with_capacity(size),
        None => Vec::new(),
    };
    io::copy(&mut raw_data, &mut src).expect("Failed reading response body while gzipping");
    let zipped = deflate_bytes_gzip(&src);
    response.data = ResponseBody::from_data(zipped);
}

#[cfg(not(feature = "gzip"))]
#[inline]
fn gzip(response: &mut Response) {}

#[cfg(feature = "brotli")]
fn brotli(response: &mut Response) {
    use brotli2::read::BrotliEncoder;
    use std::mem;
    use ResponseBody;

    response
        .headers
        .push(("Content-Encoding".into(), "br".into()));
    let previous_body = mem::replace(&mut response.data, ResponseBody::empty());
    let (raw_data, _) = previous_body.into_reader_and_size();
    response.data = ResponseBody::from_reader(BrotliEncoder::new(raw_data, 6));
}

#[cfg(not(feature = "brotli"))]
#[inline]
fn brotli(response: &mut Response) {}

#[cfg(test)]
mod tests {
    // TODO: more tests for encoding stuff
}
<|endoftext|>


<commit_before>
use error::{StoreError, StoreErrorKind};
use std::io::{Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::fs::{File, OpenOptions};

/**
 * LazyFile type
 *
 * A lazy file is either absent, but a path to it is available, or it is present.
 */
pub enum LazyFile {
    Absent(PathBuf),
    File(File)
}

fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).open(p)
}

fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).create(true).open(p)
}

impl LazyFile {

    /**
     * Create a new LazyFile instance from a Path
     */
    pub fn new(p: PathBuf) -> LazyFile {
        LazyFile::Absent(p)
    }

    /**
     * Create a new LazyFile instance from an already existing file
     */
    pub fn new_with_file(f: File) -> LazyFile {
        LazyFile::File(f)
    }

    /**
     * Get the file behind a LazyFile object
     */
    pub fn get_file(&mut self) -> Result<&File, StoreError> {
        match self.get_file_mut() {
            Ok(file) => Ok(&*file),
            Err(e) => Err(e)
        }
    }

    /**
     * Get the mutable file behind a LazyFile object
     */
    pub fn get_file_mut(&mut self) -> Result<&mut File, StoreError> {
        let file = match *self {
            LazyFile::File(ref mut f) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                f.seek(SeekFrom::Start(0)).map_err(|e|
                    StoreError::new(
                        StoreErrorKind::FileNotCreated, Some(Box::new(e))));
                Ok(f)
            },
            LazyFile::Absent(ref p) => {
                try!(open_file(p).map_err(|e| {
                    StoreError::new(StoreErrorKind::FileNotFound,
                                    Some(Box::new(e)))
                }))
            }
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }

    /**
     * Create a file out of this LazyFile object
     */
    pub fn create_file(&mut self) -> Result<&mut File, StoreError> {
        let file = match *self {
            LazyFile::File(ref mut f) => return Ok(f),
            LazyFile::Absent(ref p) => {
                try!(create_file(p).map_err(|e| {
                    StoreError::new(StoreErrorKind::FileNotFound,
                                    Some(Box::new(e)))
                }))
            }
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }
}

#[cfg(test)]
mod test {
    use super::LazyFile;
    use std::io::{Read, Write, Seek, SeekFrom};
    use std::path::PathBuf;
    use std::fs::File;
    use tempdir::TempDir;

    fn get_dir() -> TempDir {
        TempDir::new("test-image").unwrap()
    }

    #[test]
    fn lazy_file() {
        let dir = get_dir();
        let mut path = PathBuf::from(dir.path());
        path.set_file_name("test1");
        let mut lf = LazyFile::new(path);

        write!(lf.create_file().unwrap(), "Hello World").unwrap();
        dir.close().unwrap();
    }

    #[test]
    fn lazy_file_with_file() {
        let dir = get_dir();
        let mut path = PathBuf::from(dir.path());
        path.set_file_name("test2");
        let mut lf = LazyFile::new(path.clone());

        {
            let mut file = lf.create_file().unwrap();

            file.write(b"Hello World").unwrap();
            file.sync_all().unwrap();
        }

        {
            let mut file = lf.get_file().unwrap();
            let mut s = Vec::new();
            file.read_to_end(&mut s).unwrap();
            assert_eq!(s, "Hello World".to_string().into_bytes());
        }

        dir.close().unwrap();
    }
}
<commit_msg>Let LazyFile derive Debug<commit_after>
use error::{StoreError, StoreErrorKind};
use std::io::{Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::fs::{File, OpenOptions};

/**
 * LazyFile type
 *
 * A lazy file is either absent, but a path to it is available, or it is present.
 */
#[derive(Debug)]
pub enum LazyFile {
    Absent(PathBuf),
    File(File)
}

fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).open(p)
}

fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).create(true).open(p)
}

impl LazyFile {

    /**
     * Create a new LazyFile instance from a Path
     */
    pub fn new(p: PathBuf) -> LazyFile {
        LazyFile::Absent(p)
    }

    /**
     * Create a new LazyFile instance from an already existing file
     */
    pub fn new_with_file(f: File) -> LazyFile {
        LazyFile::File(f)
    }

    /**
     * Get the file behind a LazyFile object
     */
    pub fn get_file(&mut self) -> Result<&File, StoreError> {
        match self.get_file_mut() {
            Ok(file) => Ok(&*file),
            Err(e) => Err(e)
        }
    }

    /**
     * Get the mutable file behind a LazyFile object
     */
    pub fn get_file_mut(&mut self) -> Result<&mut File, StoreError> {
        let file = match *self {
            LazyFile::File(ref mut f) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                f.seek(SeekFrom::Start(0)).map_err(|e|
                    StoreError::new(
                        StoreErrorKind::FileNotCreated, Some(Box::new(e))));
                Ok(f)
            },
            LazyFile::Absent(ref p) => {
                try!(open_file(p).map_err(|e| {
                    StoreError::new(StoreErrorKind::FileNotFound,
                                    Some(Box::new(e)))
                }))
            }
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }

    /**
     * Create a file out of this LazyFile object
     */
    pub fn create_file(&mut self) -> Result<&mut File, StoreError> {
        let file = match *self {
            LazyFile::File(ref mut f) => return Ok(f),
            LazyFile::Absent(ref p) => {
                try!(create_file(p).map_err(|e| {
                    StoreError::new(StoreErrorKind::FileNotFound,
                                    Some(Box::new(e)))
                }))
            }
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }
}

#[cfg(test)]
mod test {
    use super::LazyFile;
    use std::io::{Read, Write, Seek, SeekFrom};
    use std::path::PathBuf;
    use std::fs::File;
    use tempdir::TempDir;

    fn get_dir() -> TempDir {
        TempDir::new("test-image").unwrap()
    }

    #[test]
    fn lazy_file() {
        let dir = get_dir();
        let mut path = PathBuf::from(dir.path());
        path.set_file_name("test1");
        let mut lf = LazyFile::new(path);

        write!(lf.create_file().unwrap(), "Hello World").unwrap();
        dir.close().unwrap();
    }

    #[test]
    fn lazy_file_with_file() {
        let dir = get_dir();
        let mut path = PathBuf::from(dir.path());
        path.set_file_name("test2");
        let mut lf = LazyFile::new(path.clone());

        {
            let mut file = lf.create_file().unwrap();

            file.write(b"Hello World").unwrap();
            file.sync_all().unwrap();
        }

        {
            let mut file = lf.get_file().unwrap();
            let mut s = Vec::new();
            file.read_to_end(&mut s).unwrap();
            assert_eq!(s, "Hello World".to_string().into_bytes());
        }

        dir.close().unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

/// Follows a C3 template in setting up the CPUID.
pub mod c3;
/// Follows a T2 template in setting up the CPUID.
pub mod t2;
/// Follows a T2 template for setting up the CPUID with additional MSRs
/// that are speciffic to an Intel Skylake CPU.
pub mod t2s;

use std::collections::HashSet;

use arch_gen::x86::msr_index::*;
use kvm_bindings::CpuId;

use crate::common::{get_vendor_id_from_host, VENDOR_ID_INTEL};
use crate::cpuid_is_feature_set;
use crate::transformer::Error;

pub fn validate_vendor_id() -> Result<(), Error> {
    let vendor_id = get_vendor_id_from_host()?;
    if &vendor_id != VENDOR_ID_INTEL {
        return Err(Error::InvalidVendor);
    }

    Ok(())
}

/// Returns MSRs to be saved based on the Intel CPUID features that are enabled.
pub(crate) fn msrs_to_save_by_cpuid(cpuid: &CpuId) -> HashSet<u32> {
    use crate::cpu_leaf::*;

    let mut msrs = HashSet::new();

    // Macro used for easy definition of CPUID-MSR dependencies.
    macro_rules! cpuid_msr_dep {
        ($leaf:expr, $index:expr, $reg:tt, $feature_bit:expr, $msr:expr) => {
            if cpuid_is_feature_set!(cpuid, $leaf, $index, $reg, $feature_bit) {
                msrs.extend($msr)
            }
        };
    }

    // TODO: Add more dependencies.
    cpuid_msr_dep!(
        0x7,
        0,
        ebx,
        leaf_0x7::index0::ebx::MPX_BITINDEX,
        [MSR_IA32_BNDCFGS]
    );
    msrs
}
<commit_msg>cpuid: add unit tests for msrs_to_save_by_cpuid<commit_after>// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

/// Follows a C3 template in setting up the CPUID.
pub mod c3;
/// Follows a T2 template in setting up the CPUID.
pub mod t2;
/// Follows a T2 template for setting up the CPUID with additional MSRs
/// that are speciffic to an Intel Skylake CPU.
pub mod t2s;

use std::collections::HashSet;

use arch_gen::x86::msr_index::*;
use kvm_bindings::CpuId;

use crate::common::{get_vendor_id_from_host, VENDOR_ID_INTEL};
use crate::cpuid_is_feature_set;
use crate::transformer::Error;

pub fn validate_vendor_id() -> Result<(), Error> {
    let vendor_id = get_vendor_id_from_host()?;
    if &vendor_id != VENDOR_ID_INTEL {
        return Err(Error::InvalidVendor);
    }

    Ok(())
}

/// Returns MSRs to be saved based on the Intel CPUID features that are enabled.
pub(crate) fn msrs_to_save_by_cpuid(cpuid: &CpuId) -> HashSet<u32> {
    use crate::cpu_leaf::*;

    let mut msrs = HashSet::new();

    // Macro used for easy definition of CPUID-MSR dependencies.
    macro_rules! cpuid_msr_dep {
        ($leaf:expr, $index:expr, $reg:tt, $feature_bit:expr, $msr:expr) => {
            if cpuid_is_feature_set!(cpuid, $leaf, $index, $reg, $feature_bit) {
                msrs.extend($msr)
            }
        };
    }

    // TODO: Add more dependencies.
    cpuid_msr_dep!(
        0x7,
        0,
        ebx,
        leaf_0x7::index0::ebx::MPX_BITINDEX,
        [MSR_IA32_BNDCFGS]
    );
    msrs
}

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

    #[test]
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    fn test_msrs_to_save_by_cpuid_empty() {
        // No CPUID entries are provided.
        let entrs = [];
        let cpuid = CpuId::from_entries(&entrs).unwrap();

        let msrs = msrs_to_save_by_cpuid(&cpuid);

        // No MSRs are expected to match the CPUID features.
        assert!(msrs.is_empty());
    }

    #[test]
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    fn test_msrs_to_save_by_cpuid_one() {
        use kvm_bindings::kvm_cpuid_entry2;

        use crate::cpu_leaf::leaf_0x7;

        // One CPUID entry with MPX feature flag is provided
        // that causes MSR_IA32_BNDCFGS to be pulled in.
        let entrs = [kvm_cpuid_entry2 {
            function: 0x7,
            index: 0x0,
            ebx: 1 << leaf_0x7::index0::ebx::MPX_BITINDEX,
            ..Default::default()
        }];
        let cpuid = CpuId::from_entries(&entrs).unwrap();

        let msrs = msrs_to_save_by_cpuid(&cpuid);

        // One MSR is expected to be pulled in by the CPUID feature provided.
        assert_eq!(msrs.len(), 1);

        // The expected MSR is MSR_IA32_BNDCFGS.
        assert!(msrs.contains(&MSR_IA32_BNDCFGS));
    }
}
<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;

macro_rules! set_zs {
    ($cpu_state:expr,$val:expr) => ($cpu_state.Z = $val == 0;$cpu_state.S = $val >= 0x80 );
}

macro_rules! stack_push8 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write8(0x0100 | $cpu_state.sp,$val)); $cpu_state.sp-=1;);
}
macro_rules! stack_push16 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write16(0x0100 as u16 | $cpu_state.sp as u16 -1,$val)); $cpu_state.sp-=2;);
}
macro_rules! stack_pull8 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=1;
            $mem.read8(0x0100 | $cpu_state.sp;)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}

#[derive(Debug)]
pub enum ExecutionError {
  MemoryError(::memory::MemoryError),
  UnexpectedOpcode(String),
  UnexpectedAddressMode(String)
}
impl From<::memory::MemoryError> for ExecutionError {
    fn from(err: ::memory::MemoryError) -> ExecutionError {
        ExecutionError::MemoryError(err)
    }
}

pub struct CpuExecutor {
    op_table: Vec<OpcodeExecInfo>,
}

impl CpuExecutor {
	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        CpuExecutor {
            op_table:  opcodes,
        }
    }

	/// Reset the given cpu_state.
    pub fn power_on(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        self.reset(cpu_state,mem);
    }
	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        try!(self.fetch_and_decode(cpu_state,mem));
        try!(self.execute(cpu_state,mem));
        Ok(())
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = try!(self.decode(cpu_state,mem));
        cpu_state.pc = cpu_state.pc+1;
        Ok(())
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> Result<DecodeRegister,ExecutionError> {
        let mut dr = DecodeRegister {
            info : self.op_table[cpu_state.instruction_register as usize].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.value_final = Some(mem.read8(cpu_state.pc+1).unwrap());

                // NOTE: relative is from the end of the current instruction and relative
                // instructions are 2 bytes long, so we add 2 before adding in the specified offset
                //
                if dr.value_final.unwrap() < 0x80 { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16); }
                else                              { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16 - 0x100);}
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => { return Err(ExecutionError::UnexpectedAddressMode(format!("unrecognized addressing mode '{:?}' while decoding instruction_register!",dr.info.address_mode))); }
        }

        return Ok(dr);
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) -> Result<(),ExecutionError> {
    	// Figure out which opcode is being executed.
    	match cpu_state.decode_register.info.opcode_class {
    		OpcodeClass::ASL => {
				cpu_state.a = cpu_state.a << 1;
				cpu_state.C = (128 & cpu_state.a) > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},
    		OpcodeClass::LDA => {
    			cpu_state.a = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},
    		OpcodeClass::LDX => {
    			cpu_state.x = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.x);

                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},
    		OpcodeClass::LDY => {
    			cpu_state.y = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.y);

                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},
    		OpcodeClass::LSR => {
    			cpu_state.a = cpu_state.a >> 1;
    			cpu_state.C = 1 & cpu_state.a > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},
    		OpcodeClass::JMP => {
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::JSR => {
                stack_push16!(cpu_state,mem,cpu_state.pc-1);
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::NOP => {},
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::STX => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.decode_register.value_final.unwrap()));
                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},

			_ => { return Err(ExecutionError::UnexpectedOpcode(format!("Unrecognised opcode class: {:?}", cpu_state.decode_register.info.opcode_class)));}

    	}
        Ok(())
    }
}

<commit_msg>implemented BCS opcode<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;

macro_rules! set_zs {
    ($cpu_state:expr,$val:expr) => ($cpu_state.Z = $val == 0;$cpu_state.S = $val >= 0x80 );
}

macro_rules! stack_push8 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write8(0x0100 | $cpu_state.sp,$val)); $cpu_state.sp-=1;);
}
macro_rules! stack_push16 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write16(0x0100 as u16 | $cpu_state.sp as u16 -1,$val)); $cpu_state.sp-=2;);
}
macro_rules! stack_pull8 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=1;
            $mem.read8(0x0100 | $cpu_state.sp;)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}

#[derive(Debug)]
pub enum ExecutionError {
  MemoryError(::memory::MemoryError),
  UnexpectedOpcode(String),
  UnexpectedAddressMode(String)
}
impl From<::memory::MemoryError> for ExecutionError {
    fn from(err: ::memory::MemoryError) -> ExecutionError {
        ExecutionError::MemoryError(err)
    }
}

pub struct CpuExecutor {
    op_table: Vec<OpcodeExecInfo>,
}

impl CpuExecutor {
	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        CpuExecutor {
            op_table:  opcodes,
        }
    }

	/// Reset the given cpu_state.
    pub fn power_on(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        self.reset(cpu_state,mem);
    }
	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        try!(self.fetch_and_decode(cpu_state,mem));
        try!(self.execute(cpu_state,mem));
        Ok(())
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = try!(self.decode(cpu_state,mem));
        cpu_state.pc = cpu_state.pc+1;
        Ok(())
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> Result<DecodeRegister,ExecutionError> {
        let mut dr = DecodeRegister {
            info : self.op_table[cpu_state.instruction_register as usize].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.value_final = Some(mem.read8(cpu_state.pc+1).unwrap());

                // NOTE: relative is from the end of the current instruction and relative
                // instructions are 2 bytes long, so we add 2 before adding in the specified offset
                //
                if dr.value_final.unwrap() < 0x80 { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16); }
                else                              { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16 - 0x100);}
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => { return Err(ExecutionError::UnexpectedAddressMode(format!("unrecognized addressing mode '{:?}' while decoding instruction_register!",dr.info.address_mode))); }
        }

        return Ok(dr);
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) -> Result<(),ExecutionError> {
    	// Figure out which opcode is being executed.
    	match cpu_state.decode_register.info.opcode_class {
    		OpcodeClass::ASL => {
				cpu_state.a = cpu_state.a << 1;
				cpu_state.C = (128 & cpu_state.a) > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},
    		OpcodeClass::BCS => {
                if cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
    		},
    		OpcodeClass::LDA => {
    			cpu_state.a = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},
    		OpcodeClass::LDX => {
    			cpu_state.x = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.x);

                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},
    		OpcodeClass::LDY => {
    			cpu_state.y = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.y);

                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},
    		OpcodeClass::LSR => {
    			cpu_state.a = cpu_state.a >> 1;
    			cpu_state.C = 1 & cpu_state.a > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},
    		OpcodeClass::JMP => {
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::JSR => {
                stack_push16!(cpu_state,mem,cpu_state.pc-1);
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::NOP => {},
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::STX => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.decode_register.value_final.unwrap()));
                cpu_state.pc = cpu_state.pc + (cpu_state.decode_register.info.len as u16 -1);
    		},

			_ => { return Err(ExecutionError::UnexpectedOpcode(format!("Unrecognised opcode class: {:?}", cpu_state.decode_register.info.opcode_class)));}

    	}
        Ok(())
    }
}

<|endoftext|>


<commit_before>//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
//! elements' iterator to be `Clone`.
//!
//! - [**IterDiff**](./enum.IterDiff.html) (produced by the [**iter_diff**](./fn.iter_diff.html)
//! function) describes the difference between two non-`Clone` iterators `a` and `b` after breaking
//! ASAP from a comparison with enough data to update `a`'s collection.
//! - [**copy_on_diff**](./fn.copy_on_diff.html) is an application of [**iter_diff**] that compares
//! two iterators `a` and `b`, borrowing the source of `a` if they are the same or creating a new
//! owned collection with `b`'s elements if they are different.

use std::borrow::{Cow, ToOwned};
use std::iter;

/// A type returned by the [`iter_diff`](./fn.iter_diff.html) function.
///
/// `IterDiff` represents the way in which the elements (of type `E`) yielded by the iterator `I`
/// differ to some other iterator yielding borrowed elements of the same type.
///
/// `I` is some `Iterator` yielding elements of type `E`.
pub enum IterDiff<E, I> {
    /// The index of the first non-matching element along with the iterator's remaining elements
    /// starting with the first mis-matched element.
    FirstMismatch(usize, iter::Chain<iter::Once<E>, I>),
    /// The remaining elements of the iterator.
    Longer(iter::Chain<iter::Once<E>, I>),
    /// The total number of elements that were in the iterator.
    Shorter(usize),
}

/// Compares every element yielded by both elems and new_elems in lock-step and returns an
/// `IterDiff` which describes how `b` differs from `a`.
///
/// This function is useful for caching some iterator `b` in some sequential collection without
/// requiring `b` to be `Clone` in order to compare it to the collection before determining if the
/// collection needs to be updated. The returned function returns as soon as a difference is found,
/// producing an `IterDiff` that provides the data necessary to update the collection without ever
/// requiring `B` to be `Clone`. This allows for efficintly caching iterators like `Map` or
/// `Filter` that do not implement `Clone`.
///
/// If the number of elements yielded by `b` is less than the number of elements yielded by `a`,
/// the number of `b` elements yielded will be returned as `IterDiff::Shorter`.
///
/// If the two elements of a step differ, the index of those elements along with the remaining
/// elements of `b` are returned as `IterDiff::FirstMismatch`.
///
/// If `a` becomes exhausted before `b` becomes exhausted, the remaining `b` elements will be
/// returned as `IterDiff::Longer`.
///
/// See [`copy_on_diff`](./fn.copy_on_diff.html) for an application of `iter_diff`.
pub fn iter_diff<'a, A, B>(a: A, b: B) -> Option<IterDiff<B::Item, B::IntoIter>>
    where A: IntoIterator<Item=&'a B::Item>,
          B: IntoIterator,
          B::Item: PartialEq + 'a,
{
    let mut b = b.into_iter();
    for (i, a_elem) in a.into_iter().enumerate() {
        match b.next() {
            None => return Some(IterDiff::Shorter(i)),
            Some(b_elem) => if *a_elem != b_elem {
                return Some(IterDiff::FirstMismatch(i, iter::once(b_elem).chain(b)));
            },
        }
    }
    b.next().map(|elem| IterDiff::Longer(iter::once(elem).chain(b)))
}

/// Returns `Cow::Borrowed` `a` if `a` contains the same elements as yielded by `b`'s iterator.
///
/// Collects into a new `A::Owned` and returns `Cow::Owned` if either the number of elements or the
/// elements themselves differ.
///
/// # Examples
///
/// ```
/// use itertools::copy_on_diff;
/// use std::borrow::Cow;
///
/// let a = vec![0, 1, 2];
/// let b = vec![0.0, 1.0, 2.0];
/// let b_map = b.into_iter().map(|f| f as i32);
/// let a_cow = copy_on_diff(&a, b_map);
///
/// assert!(match a_cow {
///     Cow::Borrowed(slice) => slice == &a,
///     _ => false,
/// });
/// ```
///
/// ```
/// use itertools::copy_on_diff;
/// use std::borrow::Cow;
///
/// let a = vec![0, 1, 2, 3];
/// let b = vec![0.0, 1.0, 2.0];
/// let b_map = b.into_iter().map(|f| f as i32);
/// let a_cow = copy_on_diff(&a, b_map);
///
/// assert!(match a_cow {
///     Cow::Owned(vec) => vec == vec![0, 1, 2],
///     _ => false,
/// });
/// ```
pub fn copy_on_diff<'a, A, B, T: 'a>(a: &'a A, b: B) -> Cow<'a, A>
    where &'a A: IntoIterator<Item=&'a T>,
          <&'a A as IntoIterator>::IntoIter: Clone,
          A: ToOwned,
          <A as ToOwned>::Owned: iter::FromIterator<T>,
          B: IntoIterator<Item=T>,
          T: Clone + PartialEq,
{
    let a_iter = a.into_iter();
    match iter_diff(a_iter.clone(), b.into_iter()) {
        Some(IterDiff::FirstMismatch(i, mismatch)) =>
            Cow::Owned(a_iter.take(i).cloned().chain(mismatch).collect()),
        Some(IterDiff::Longer(remaining)) =>
            Cow::Owned(a_iter.cloned().chain(remaining).collect()),
        Some(IterDiff::Shorter(num_new_elems)) =>
            Cow::Owned(a_iter.cloned().take(num_new_elems).collect()),
        None => Cow::Borrowed(a),
    }
}
<commit_msg>Fix typo in docs<commit_after>//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
//! elements' iterator to be `Clone`.
//!
//! - [**IterDiff**](./enum.IterDiff.html) (produced by the [**iter_diff**](./fn.iter_diff.html)
//! function) describes the difference between two non-`Clone` iterators `a` and `b` after breaking
//! ASAP from a comparison with enough data to update `a`'s collection.
//! - [**copy_on_diff**](./fn.copy_on_diff.html) is an application of [**iter_diff**] that compares
//! two iterators `a` and `b`, borrowing the source of `a` if they are the same or creating a new
//! owned collection with `b`'s elements if they are different.

use std::borrow::{Cow, ToOwned};
use std::iter;

/// A type returned by the [`iter_diff`](./fn.iter_diff.html) function.
///
/// `IterDiff` represents the way in which the elements (of type `E`) yielded by the iterator `I`
/// differ to some other iterator yielding borrowed elements of the same type.
///
/// `I` is some `Iterator` yielding elements of type `E`.
pub enum IterDiff<E, I> {
    /// The index of the first non-matching element along with the iterator's remaining elements
    /// starting with the first mis-matched element.
    FirstMismatch(usize, iter::Chain<iter::Once<E>, I>),
    /// The remaining elements of the iterator.
    Longer(iter::Chain<iter::Once<E>, I>),
    /// The total number of elements that were in the iterator.
    Shorter(usize),
}

/// Compares every element yielded by both elems and new_elems in lock-step and returns an
/// `IterDiff` which describes how `b` differs from `a`.
///
/// This function is useful for caching some iterator `b` in some sequential collection without
/// requiring `b` to be `Clone` in order to compare it to the collection before determining if the
/// collection needs to be updated. The returned function returns as soon as a difference is found,
/// producing an `IterDiff` that provides the data necessary to update the collection without ever
/// requiring `B` to be `Clone`. This allows for efficiently caching iterators like `Map` or
/// `Filter` that do not implement `Clone`.
///
/// If the number of elements yielded by `b` is less than the number of elements yielded by `a`,
/// the number of `b` elements yielded will be returned as `IterDiff::Shorter`.
///
/// If the two elements of a step differ, the index of those elements along with the remaining
/// elements of `b` are returned as `IterDiff::FirstMismatch`.
///
/// If `a` becomes exhausted before `b` becomes exhausted, the remaining `b` elements will be
/// returned as `IterDiff::Longer`.
///
/// See [`copy_on_diff`](./fn.copy_on_diff.html) for an application of `iter_diff`.
pub fn iter_diff<'a, A, B>(a: A, b: B) -> Option<IterDiff<B::Item, B::IntoIter>>
    where A: IntoIterator<Item=&'a B::Item>,
          B: IntoIterator,
          B::Item: PartialEq + 'a,
{
    let mut b = b.into_iter();
    for (i, a_elem) in a.into_iter().enumerate() {
        match b.next() {
            None => return Some(IterDiff::Shorter(i)),
            Some(b_elem) => if *a_elem != b_elem {
                return Some(IterDiff::FirstMismatch(i, iter::once(b_elem).chain(b)));
            },
        }
    }
    b.next().map(|elem| IterDiff::Longer(iter::once(elem).chain(b)))
}

/// Returns `Cow::Borrowed` `a` if `a` contains the same elements as yielded by `b`'s iterator.
///
/// Collects into a new `A::Owned` and returns `Cow::Owned` if either the number of elements or the
/// elements themselves differ.
///
/// # Examples
///
/// ```
/// use itertools::copy_on_diff;
/// use std::borrow::Cow;
///
/// let a = vec![0, 1, 2];
/// let b = vec![0.0, 1.0, 2.0];
/// let b_map = b.into_iter().map(|f| f as i32);
/// let a_cow = copy_on_diff(&a, b_map);
///
/// assert!(match a_cow {
///     Cow::Borrowed(slice) => slice == &a,
///     _ => false,
/// });
/// ```
///
/// ```
/// use itertools::copy_on_diff;
/// use std::borrow::Cow;
///
/// let a = vec![0, 1, 2, 3];
/// let b = vec![0.0, 1.0, 2.0];
/// let b_map = b.into_iter().map(|f| f as i32);
/// let a_cow = copy_on_diff(&a, b_map);
///
/// assert!(match a_cow {
///     Cow::Owned(vec) => vec == vec![0, 1, 2],
///     _ => false,
/// });
/// ```
pub fn copy_on_diff<'a, A, B, T: 'a>(a: &'a A, b: B) -> Cow<'a, A>
    where &'a A: IntoIterator<Item=&'a T>,
          <&'a A as IntoIterator>::IntoIter: Clone,
          A: ToOwned,
          <A as ToOwned>::Owned: iter::FromIterator<T>,
          B: IntoIterator<Item=T>,
          T: Clone + PartialEq,
{
    let a_iter = a.into_iter();
    match iter_diff(a_iter.clone(), b.into_iter()) {
        Some(IterDiff::FirstMismatch(i, mismatch)) =>
            Cow::Owned(a_iter.take(i).cloned().chain(mismatch).collect()),
        Some(IterDiff::Longer(remaining)) =>
            Cow::Owned(a_iter.cloned().chain(remaining).collect()),
        Some(IterDiff::Shorter(num_new_elems)) =>
            Cow::Owned(a_iter.cloned().take(num_new_elems).collect()),
        None => Cow::Borrowed(a),
    }
}
<|endoftext|>


<commit_before>use std::ops::Add;
use ndarray;

type TileArray = ndarray::Array2<Tile>;
// Index into a TileArray; arrays are indexed in (row (y), column (x)) order
type TileIndex = (usize, usize);

impl Add<Direction> for TileIndex {
    type Output = TileIndex;

    fn add(self, direction: Direction) -> TileIndex {
        let (y, x) = self;
        match direction {
            Direction::Up => (y - 1, x),
            Direction::Down => (y + 1, x),
            Direction::Left => (y, x - 1),
            Direction::Right => (y, x + 1),
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

pub struct GameState {
    tiles: TileArray,
    snake_head: TileIndex,
    snake_tail: TileIndex,
    snake_dir: Direction,
}

impl GameState {
    pub fn new() -> Self {
        let width = 80;
        let height = 50;
        let mut tiles = ndarray::Array::from_elem((height, width), Tile::Floor);

        // Build level wall
        for x in 0..width {
            tiles[(0, x)] = Tile::Wall;
            tiles[(height - 1, x)] = Tile::Wall;
        }
        for y in 0..height {
            tiles[(y, 0)] = Tile::Wall;
            tiles[(y, width - 1)] = Tile::Wall;
        }

        // Place snake
        tiles[(3, 3)] = Tile::Snake(Some((3, 4)));
        tiles[(3, 4)] = Tile::Snake(Some((3, 5)));
        tiles[(3, 5)] = Tile::Snake(None);
        let snake_head = (3, 5);
        let snake_tail = (3, 3);
        let snake_dir = Direction::Right;

        Self {
            tiles: tiles,
            snake_head: snake_head,
            snake_tail: snake_tail,
            snake_dir: snake_dir,
        }
    }

    pub fn tiles(&self) -> &TileArray {
        &self.tiles
    }

    pub fn set_snake_dir(&mut self, new_snake_dir: Direction) {
        self.snake_dir = new_snake_dir;
    }

    pub fn update(&mut self) {
        // Move snake
        let new_snake_head = self.snake_head + self.snake_dir;
        // Handle collision
        match self.tiles[new_snake_head] {
            Tile::Wall | Tile::Snake(_) => {
                // New head collides with wall or snake, so game over
                // FIXME Implement game over, just return for now
                return;
            }
            Tile::Food => {
                // New head collides with food, so eat the food
                // FIXME Spawn new food; adjust score
            }
            Tile::Floor => (), // No collision
        }
        self.tiles[self.snake_head] = Tile::Snake(Some(new_snake_head));
        self.tiles[new_snake_head] = Tile::Snake(None);
        self.snake_head = new_snake_head;
        if let Tile::Snake(Some(new_snake_tail)) = self.tiles[self.snake_tail] {
            self.tiles[self.snake_tail] = Tile::Floor;
            self.snake_tail = new_snake_tail;
        } else {
            panic!("Expected Snake(Some(_)) on tile at position {:?}, found {:?} instead",
                   self.snake_tail,
                   self.tiles[self.snake_tail]);
        }
    }
}

impl Default for GameState {
    fn default() -> Self {
        Self::new()
    }
}

#[derive(Copy, Clone, Debug)]
pub enum Tile {
    Floor,
    Wall,
    Food,
    // A Snake tile contains the index of the next tile of the snake (pointing towards the
    // head of the snake, which is the only Snake tile without an index)
    Snake(Option<TileIndex>),
}
<commit_msg>Have Snake tile contain direction instead of index<commit_after>use std::ops::Add;
use ndarray;

type TileArray = ndarray::Array2<Tile>;
// Index into a TileArray; arrays are indexed in (row (y), column (x)) order
type TileIndex = (usize, usize);

impl Add<Direction> for TileIndex {
    type Output = TileIndex;

    fn add(self, direction: Direction) -> TileIndex {
        let (y, x) = self;
        match direction {
            Direction::Up => (y - 1, x),
            Direction::Down => (y + 1, x),
            Direction::Left => (y, x - 1),
            Direction::Right => (y, x + 1),
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

pub struct GameState {
    tiles: TileArray,
    snake_head: TileIndex,
    snake_tail: TileIndex,
    snake_dir: Direction,
}

impl GameState {
    pub fn new() -> Self {
        let width = 80;
        let height = 50;
        let mut tiles = ndarray::Array::from_elem((height, width), Tile::Floor);

        // Build level wall
        for x in 0..width {
            tiles[(0, x)] = Tile::Wall;
            tiles[(height - 1, x)] = Tile::Wall;
        }
        for y in 0..height {
            tiles[(y, 0)] = Tile::Wall;
            tiles[(y, width - 1)] = Tile::Wall;
        }

        // Place snake
        tiles[(3, 3)] = Tile::Snake(Direction::Right);
        tiles[(3, 4)] = Tile::Snake(Direction::Right);
        tiles[(3, 5)] = Tile::Snake(Direction::Right);
        let snake_head = (3, 5);
        let snake_tail = (3, 3);
        let snake_dir = Direction::Right;

        Self {
            tiles: tiles,
            snake_head: snake_head,
            snake_tail: snake_tail,
            snake_dir: snake_dir,
        }
    }

    pub fn tiles(&self) -> &TileArray {
        &self.tiles
    }

    pub fn set_snake_dir(&mut self, new_snake_dir: Direction) {
        self.snake_dir = new_snake_dir;
    }

    pub fn update(&mut self) {
        // Move snake
        let new_snake_head = self.snake_head + self.snake_dir;
        // Handle collision
        match self.tiles[new_snake_head] {
            Tile::Wall | Tile::Snake(_) => {
                // New head collides with wall or snake, so game over
                // FIXME Implement game over, just return for now
                return;
            }
            Tile::Food => {
                // New head collides with food, so eat the food
                // FIXME Spawn new food; adjust score
            }
            Tile::Floor => (), // No collision
        }
        self.tiles[self.snake_head] = Tile::Snake(self.snake_dir);
        self.tiles[new_snake_head] = Tile::Snake(self.snake_dir);
        self.snake_head = new_snake_head;
        if let Tile::Snake(snake_tail_dir) = self.tiles[self.snake_tail] {
            self.tiles[self.snake_tail] = Tile::Floor;
            self.snake_tail = self.snake_tail + snake_tail_dir;
        } else {
            panic!("Expected Snake(_) on tile at position {:?}, found {:?} instead",
                   self.snake_tail,
                   self.tiles[self.snake_tail]);
        }
    }
}

impl Default for GameState {
    fn default() -> Self {
        Self::new()
    }
}

#[derive(Copy, Clone, Debug)]
pub enum Tile {
    Floor,
    Wall,
    Food,
    // A Snake tile contains the direction that part of the snake is moving in (pointing towards
    // the head of the snake)
    Snake(Direction),
}
<|endoftext|>


<commit_before>#![feature(globs)]

extern crate libc;
extern crate neovim;
extern crate rgtk;
extern crate serialize;

use neovim::nvim_main;
use rgtk::*;
use std::collections::HashSet;
use std::{io, os, str, time};

mod projects;
mod ui;
mod utils;

mod ffi {
    pub use libc::{c_int, c_uchar, c_void};
    pub use libc::funcs::posix88::unistd::{close, pipe, read, write};
    pub use libc::types::os::arch::c95::size_t;

    extern "C" {
        pub fn fork () -> c_int;
        pub fn kill (pid: c_int, sig: c_int);
    }
}

fn gui_main(
    pty: &mut gtk::VtePty,
    read_fd: ffi::c_int,
    write_fd: ffi::c_int,
    pid: ffi::c_int)
{
    gtk::init();

    // constants

    let width = 1242;
    let height = 768;
    let editor_height = ((height as f32) * 0.75) as i32;

    // create the window

    let title = format!("SolidOak {}.{}.{}",
                        option_env!("CARGO_PKG_VERSION_MAJOR").unwrap(),
                        option_env!("CARGO_PKG_VERSION_MINOR").unwrap(),
                        option_env!("CARGO_PKG_VERSION_PATCH").unwrap());
    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    window.set_title(title.as_slice());
    window.set_window_position(gtk::WindowPosition::Center);
    window.set_default_size(width, height);

    window.connect(gtk::signals::DeleteEvent::new(|_| {
        unsafe {
            ffi::close(read_fd);
            ffi::close(write_fd);
            ffi::kill(pid, 15);
        }
        gtk::main_quit();
        true
    }));

    // create the panes

    let new_button = gtk::Button::new_with_label("New Project").unwrap();
    let import_button = gtk::Button::new_with_label("Import").unwrap();
    let rename_button = gtk::Button::new_with_label("Rename").unwrap();
    let remove_button = gtk::Button::new_with_label("Remove").unwrap();

    let mut project_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    project_buttons.set_size_request(-1, -1);
    project_buttons.add(&new_button);
    project_buttons.add(&import_button);
    project_buttons.add(&rename_button);
    project_buttons.add(&remove_button);

    let mut project_tree = gtk::TreeView::new().unwrap();
    let selection = project_tree.get_selection().unwrap();
    let column_types = [glib::ffi::g_type_string, glib::ffi::g_type_string];
    let store = gtk::TreeStore::new(&column_types).unwrap();
    let model = store.get_model().unwrap();
    project_tree.set_model(&model);
    project_tree.set_headers_visible(false);

    let mut scroll_pane = gtk::ScrolledWindow::new(None, None).unwrap();
    scroll_pane.add(&project_tree);

    let column = gtk::TreeViewColumn::new().unwrap();
    let cell = gtk::CellRendererText::new().unwrap();
    column.pack_start(&cell, true);
    column.add_attribute(&cell, "text", 0);
    project_tree.append_column(&column);

    let mut project_pane = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    project_pane.set_size_request(-1, -1);
    project_pane.pack_start(&project_buttons, false, true, 0);
    project_pane.pack_start(&scroll_pane, true, true, 0);

    let mut editor_pane = gtk::VteTerminal::new().unwrap();
    editor_pane.set_size_request(-1, editor_height);
    editor_pane.set_pty(pty);
    editor_pane.watch_child(pid);

    let run_button = gtk::Button::new_with_label("Run").unwrap();
    let build_button = gtk::Button::new_with_label("Build").unwrap();
    let test_button = gtk::Button::new_with_label("Test").unwrap();
    let clean_button = gtk::Button::new_with_label("Clean").unwrap();
    let stop_button = gtk::Button::new_with_label("Stop").unwrap();

    let mut build_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    build_buttons.set_size_request(-1, -1);
    build_buttons.add(&run_button);
    build_buttons.add(&build_button);
    build_buttons.add(&test_button);
    build_buttons.add(&clean_button);
    build_buttons.add(&stop_button);

    let build_term = gtk::VteTerminal::new().unwrap();

    let mut build_pane = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    build_pane.pack_start(&build_buttons, false, true, 0);
    build_pane.pack_start(&build_term, true, true, 0);

    let mut content = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    content.pack_start(&editor_pane, false, true, 0);
    content.pack_start(&build_pane, true, true, 0);

    let mut hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    hbox.pack_start(&project_pane, false, true, 0);
    hbox.pack_start(&content, true, true, 0);
    window.add(&hbox);

    // populate the project tree

    let mut state = ::utils::State{
        projects: HashSet::new(),
        expansions: HashSet::new(),
        selection: None,
        tree_model: &model,
        tree_store: &store,
        tree_selection: &selection,
        rename_button: &rename_button,
        remove_button: &remove_button,
    };

    ::utils::create_data_dir();
    ::utils::read_prefs(&mut state);
    ::ui::update_project_tree(&mut state, &mut project_tree);

    // connect to the signals

    new_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::new_project(&mut state, &mut project_tree);
    }));
    import_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::import_project(&mut state, &mut project_tree);
    }));
    rename_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::rename_file(&mut state);
    }));
    remove_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::remove_item(&mut state);
    }));
    selection.connect(gtk::signals::Changed::new(|| {
        ::projects::save_selection(&mut state);
    }));
    project_tree.connect(gtk::signals::RowCollapsed::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::remove_expansion(&mut state, &iter);
    }));
    project_tree.connect(gtk::signals::RowExpanded::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::add_expansion(&mut state, &iter);
    }));

    // show the window

    window.show_all();
    gtk::main();
}

fn main() {
    // takes care of piping stdin/stdout between the gui and nvim
    let mut pty = gtk::VtePty::new().unwrap();

    // two pairs of anonymous pipes for msgpack-rpc between the gui and nvim
    let mut nvim_from_gui : [ffi::c_int, ..2] = [0, ..2];
    let mut gui_from_nvim : [ffi::c_int, ..2] = [0, ..2];
    unsafe {
        ffi::pipe(nvim_from_gui.as_mut_ptr());
        ffi::pipe(gui_from_nvim.as_mut_ptr());
    };

    // split into two processes
    let pid = unsafe { ffi::fork() };

    if pid > 0 { // the gui process
        // listen for messages from nvim
        spawn(proc() {
            let mut buf : [ffi::c_uchar, ..100] = [0, ..100];
            unsafe {
                loop {
                    let buf_ptr = buf.as_mut_ptr() as *mut ffi::c_void;
                    let n = ffi::read(gui_from_nvim[0], buf_ptr, 100);
                    if n < 0 {
                        break;
                    } else if n > 0 {
                        let msg = str::from_utf8(buf.slice_to(n as uint)).unwrap();
                        println!("Received: {}", msg);
                    }
                }
            }
        });

        // start the gui
        gui_main(&mut pty, gui_from_nvim[0], gui_from_nvim[1], pid);
    } else { // the nvim process
        // prepare this process to be piped into the gui
        pty.child_setup();

        // listen for messages from the gui
        spawn(proc() {
            io::timer::sleep(time::Duration::seconds(1));

            let mut ch = neovim::Channel::new(nvim_from_gui[0], gui_from_nvim[1]);
            ch.subscribe("test");

            unsafe {
                let msg = "Hello, world!";
                let msg_c = msg.to_c_str();
                let msg_ptr = msg_c.as_ptr() as *const ffi::c_void;
                ffi::write(gui_from_nvim[1], msg_ptr, msg_c.len() as ffi::size_t);
            }
        });

        // start nvim
        nvim_main(os::args());
    }
}
<commit_msg>Rename functions<commit_after>#![feature(globs)]

extern crate libc;
extern crate neovim;
extern crate rgtk;
extern crate serialize;

use rgtk::*;
use std::collections::HashSet;
use std::{io, os, str, time};

mod projects;
mod ui;
mod utils;

mod ffi {
    pub use libc::{c_int, c_uchar, c_void};
    pub use libc::funcs::posix88::unistd::{close, pipe, read, write};
    pub use libc::types::os::arch::c95::size_t;

    extern "C" {
        pub fn fork () -> c_int;
        pub fn kill (pid: c_int, sig: c_int);
    }
}

fn gui_main(
    pty: &mut gtk::VtePty,
    read_fd: ffi::c_int,
    write_fd: ffi::c_int,
    pid: ffi::c_int)
{
    gtk::init();

    // constants

    let width = 1242;
    let height = 768;
    let editor_height = ((height as f32) * 0.75) as i32;

    // create the window

    let title = format!("SolidOak {}.{}.{}",
                        option_env!("CARGO_PKG_VERSION_MAJOR").unwrap(),
                        option_env!("CARGO_PKG_VERSION_MINOR").unwrap(),
                        option_env!("CARGO_PKG_VERSION_PATCH").unwrap());
    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    window.set_title(title.as_slice());
    window.set_window_position(gtk::WindowPosition::Center);
    window.set_default_size(width, height);

    window.connect(gtk::signals::DeleteEvent::new(|_| {
        unsafe {
            ffi::close(read_fd);
            ffi::close(write_fd);
            ffi::kill(pid, 15);
        }
        gtk::main_quit();
        true
    }));

    // create the panes

    let new_button = gtk::Button::new_with_label("New Project").unwrap();
    let import_button = gtk::Button::new_with_label("Import").unwrap();
    let rename_button = gtk::Button::new_with_label("Rename").unwrap();
    let remove_button = gtk::Button::new_with_label("Remove").unwrap();

    let mut project_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    project_buttons.set_size_request(-1, -1);
    project_buttons.add(&new_button);
    project_buttons.add(&import_button);
    project_buttons.add(&rename_button);
    project_buttons.add(&remove_button);

    let mut project_tree = gtk::TreeView::new().unwrap();
    let selection = project_tree.get_selection().unwrap();
    let column_types = [glib::ffi::g_type_string, glib::ffi::g_type_string];
    let store = gtk::TreeStore::new(&column_types).unwrap();
    let model = store.get_model().unwrap();
    project_tree.set_model(&model);
    project_tree.set_headers_visible(false);

    let mut scroll_pane = gtk::ScrolledWindow::new(None, None).unwrap();
    scroll_pane.add(&project_tree);

    let column = gtk::TreeViewColumn::new().unwrap();
    let cell = gtk::CellRendererText::new().unwrap();
    column.pack_start(&cell, true);
    column.add_attribute(&cell, "text", 0);
    project_tree.append_column(&column);

    let mut project_pane = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    project_pane.set_size_request(-1, -1);
    project_pane.pack_start(&project_buttons, false, true, 0);
    project_pane.pack_start(&scroll_pane, true, true, 0);

    let mut editor_pane = gtk::VteTerminal::new().unwrap();
    editor_pane.set_size_request(-1, editor_height);
    editor_pane.set_pty(pty);
    editor_pane.watch_child(pid);

    let run_button = gtk::Button::new_with_label("Run").unwrap();
    let build_button = gtk::Button::new_with_label("Build").unwrap();
    let test_button = gtk::Button::new_with_label("Test").unwrap();
    let clean_button = gtk::Button::new_with_label("Clean").unwrap();
    let stop_button = gtk::Button::new_with_label("Stop").unwrap();

    let mut build_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    build_buttons.set_size_request(-1, -1);
    build_buttons.add(&run_button);
    build_buttons.add(&build_button);
    build_buttons.add(&test_button);
    build_buttons.add(&clean_button);
    build_buttons.add(&stop_button);

    let build_term = gtk::VteTerminal::new().unwrap();

    let mut build_pane = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    build_pane.pack_start(&build_buttons, false, true, 0);
    build_pane.pack_start(&build_term, true, true, 0);

    let mut content = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    content.pack_start(&editor_pane, false, true, 0);
    content.pack_start(&build_pane, true, true, 0);

    let mut hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    hbox.pack_start(&project_pane, false, true, 0);
    hbox.pack_start(&content, true, true, 0);
    window.add(&hbox);

    // populate the project tree

    let mut state = ::utils::State{
        projects: HashSet::new(),
        expansions: HashSet::new(),
        selection: None,
        tree_model: &model,
        tree_store: &store,
        tree_selection: &selection,
        rename_button: &rename_button,
        remove_button: &remove_button,
    };

    ::utils::create_data_dir();
    ::utils::read_prefs(&mut state);
    ::ui::update_project_tree(&mut state, &mut project_tree);

    // connect to the signals

    new_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::new_project(&mut state, &mut project_tree);
    }));
    import_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::import_project(&mut state, &mut project_tree);
    }));
    rename_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::rename_file(&mut state);
    }));
    remove_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::remove_item(&mut state);
    }));
    selection.connect(gtk::signals::Changed::new(|| {
        ::projects::save_selection(&mut state);
    }));
    project_tree.connect(gtk::signals::RowCollapsed::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::remove_expansion(&mut state, &iter);
    }));
    project_tree.connect(gtk::signals::RowExpanded::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::add_expansion(&mut state, &iter);
    }));

    // show the window

    window.show_all();
    gtk::main();
}

fn main() {
    // takes care of piping stdin/stdout between the gui and nvim
    let mut pty = gtk::VtePty::new().unwrap();

    // two pairs of anonymous pipes for msgpack-rpc between the gui and nvim
    let mut nvim_from_gui : [ffi::c_int, ..2] = [0, ..2];
    let mut gui_from_nvim : [ffi::c_int, ..2] = [0, ..2];
    unsafe {
        ffi::pipe(nvim_from_gui.as_mut_ptr());
        ffi::pipe(gui_from_nvim.as_mut_ptr());
    };

    // split into two processes
    let pid = unsafe { ffi::fork() };

    if pid > 0 { // the gui process
        // listen for messages from nvim
        spawn(proc() {
            let mut buf : [ffi::c_uchar, ..100] = [0, ..100];
            unsafe {
                loop {
                    let buf_ptr = buf.as_mut_ptr() as *mut ffi::c_void;
                    let n = ffi::read(gui_from_nvim[0], buf_ptr, 100);
                    if n < 0 {
                        break;
                    } else if n > 0 {
                        let msg = str::from_utf8(buf.slice_to(n as uint)).unwrap();
                        println!("Received: {}", msg);
                    }
                }
            }
        });

        // start the gui
        gui_main(&mut pty, gui_from_nvim[0], gui_from_nvim[1], pid);
    } else { // the nvim process
        // prepare this process to be piped into the gui
        pty.child_setup();

        // listen for messages from the gui
        spawn(proc() {
            io::timer::sleep(time::Duration::seconds(1));

            let mut ch = neovim::Channel::new_with_fds(nvim_from_gui[0], gui_from_nvim[1]);
            ch.subscribe("test");

            unsafe {
                let msg = "Hello, world!";
                let msg_c = msg.to_c_str();
                let msg_ptr = msg_c.as_ptr() as *const ffi::c_void;
                ffi::write(gui_from_nvim[1], msg_ptr, msg_c.len() as ffi::size_t);
            }
        });

        // start nvim
        neovim::run_with_vec(os::args());
    }
}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]
#![allow(dead_code)]

extern crate artificial_genome;
extern crate rand;

use artificial_genome::{Genome, ProteinRegulator, GeneNetwork, GeneNetworkState};
use artificial_genome::base4::{Base4, B0, B1};
// use std::str::FromStr;
use std::mem;
use std::borrow::Cow;
use std::io::{self, Write};

#[derive(Debug, Clone)]
struct Edge {
    src_node: usize,
    dst_node: usize,
    length: f32,
    // Every edge has it's own regulatory network state embedded.
    network_state: GeneNetworkState,
}

impl Edge {
    fn develop(&mut self,
               network: &GeneNetwork,
               next_node_id: &mut usize,
               new_edges: &mut Vec<Edge>) {
        // first perform the state transition.
        // for each node, iterate over all incoming edges. sum

        // create an empty new state.
        let mut new_state = network.new_state();

        for (i, node) in network.nodes().iter().enumerate() {
            // determine the new state of ```node``` (position i in new_state)
            if node.sum_edges(&self.network_state) > 0 {
                // node is enabled
                new_state.state.insert(i);
            }
        }

        println!("previous state: {:?}", self.network_state);
        self.network_state = new_state;
        println!("new state: {:?}", self.network_state);

        // perform the actions of all active nodes in the gene network. then transition the network to
        // the next state.

        // first node is used for differentiation. in a split/duplicate node, this
        // will be set 0 or 1 in the children.
        // starting from second node, the nodes are mapped to graph grammar rules.

        // fixed map from node-id to graph rule. first node is used for differentiation
        // of the edges when a new edge is created.
        //

        if self.network_state.state.contains(1) {
            // GraphGrammar::Split
            let new_node = *next_node_id;
            *next_node_id += 1;

            // differentiate
            let mut child_state = self.network_state.clone();
            child_state.state.set(0, !self.network_state.state.contains(0));

            let new_edge = Edge {
                src_node: new_node,
                dst_node: self.dst_node,
                length: 0.5 * self.length,
                network_state: child_state,
            };
            self.dst_node = new_node;
            self.length *= 0.5;
            new_edges.push(new_edge);
        }

        if self.network_state.state.contains(2) {
            // GraphGrammar::Duplicate

            // differentiate
            let mut child_state = self.network_state.clone();
            child_state.state.set(0, !self.network_state.state.contains(0));

            let new_edge = Edge {
                src_node: self.src_node,
                dst_node: self.dst_node,
                length: self.length,
                network_state: child_state,
            };
            new_edges.push(new_edge);
        }

        if self.network_state.state.contains(3) {
            // GraphGrammar::Swap
            mem::swap(&mut self.dst_node, &mut self.src_node);
        }

        if self.network_state.state.contains(4) {
            // GraphGrammar::Resize grow
            self.length *= 1.25;
        }

        if self.network_state.state.contains(5) {
            // GraphGrammar::Resize shrink
            self.length *= 0.75;
        }
    }
}

#[derive(Debug)]
struct GraphBuilder {
    edges: Vec<Edge>,
    next_node_id: usize,
    network: GeneNetwork,
}

impl GraphBuilder {
    fn new(network: GeneNetwork, zygote: GeneNetworkState) -> GraphBuilder {
        let initial_edge = Edge {
            src_node: 0,
            dst_node: 1,
            length: 1.0,
            network_state: zygote,
        };

        GraphBuilder {
            edges: vec![initial_edge],
            next_node_id: 2,
            network: network,
        }
    }

    // During the process, some edges will be added (split), some others will be modified.
    fn next(&mut self) {
        let mut new_edges = Vec::new();
        for edge in self.edges.iter_mut() {
            edge.develop(&self.network, &mut self.next_node_id, &mut new_edges);
        }
        println!("next_node_id: {}", self.next_node_id);
        println!("new edges: {:?}", new_edges);
        self.edges.extend(new_edges);
    }

    fn write_dot<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        try!(writeln!(wr, "digraph artificial {{"));

        /*
        let mut nodes = Vec::new();
        for edge in self.edges.iter() {
            nodes.push(edge.src_node);
            nodes.push(edge.dst_node);
        }
        nodes.sort();
        nodes.dedup();

        for (i, node) in nodes.iter().enumerate() {
            try!(writeln!(wr, "N{} [label=\"{}\"];", i, i));
        }
        */

        //for i in 0..self.next_node_id {
            //try!(writeln!(wr, "{}", i));
        //}

        for edge in self.edges.iter() {
            try!(writeln!(wr, "{} -> {} [weight={}]", edge.src_node, edge.dst_node, edge.length));
        }

        try!(writeln!(wr, "}}"));

        Ok(())
    }
}

fn main() {
    use std::fs::File;
    // let genome = Genome::<Base4>::from_str("...11 _0320_23 <0101> T:0311 2...3 _1022_ 133 <0101> \
    // W:3213 121...")
    let mut rng = rand::thread_rng();

    let genome = Genome::<Base4>::random(&mut rng, 10 * 256);

    // let promoter = BaseString::<Base4>::from_str("0101").unwrap();
    let promoter = [B0, B1, B0, B1];

    let genes: Vec<_> = genome.iter_genes(&promoter, 4).collect();
    println!("{:?}", genes);

    let network = genome.construct_network(&promoter,
                                           4,
                                           &|product| {
                                               if product.last() == Some(&B0) {
                                                   // Inhibitor
                                                   ProteinRegulator::inhibit()
                                               } else {
                                                   // Inhibitor
                                                   ProteinRegulator::enhance()
                                               }
                                           });

    println!("{:#?}", network);

    let mut zygote = network.new_state();
    zygote.state.set(0, true);
    zygote.state.set(1, true);

    let mut gb = GraphBuilder::new(network, zygote);
    println!("{:#?}", gb);

    for i in 0..3 {
        gb.next();
    }
    println!("{:#?}", gb);

    gb.write_dot(&mut File::create("example1.dot").unwrap());
}
<commit_msg>Cleanup<commit_after>#![feature(slice_patterns)]
#![allow(dead_code)]

extern crate artificial_genome;
extern crate rand;

use artificial_genome::{Genome, ProteinRegulator, GeneNetwork, GeneNetworkState};
use artificial_genome::base4::{Base4, B0, B1};
// use std::str::FromStr;
use std::mem;
use std::borrow::Cow;
use std::io::{self, Write};

#[derive(Debug, Clone)]
struct Edge {
    src_node: usize,
    dst_node: usize,
    length: f32,

    // there is a structural node, and each time it is activated,
    // this count is increased.
    type_count: usize,

    // Every edge has it's own regulatory network state embedded.
    network_state: GeneNetworkState,
}

const EDGE_DIFFERENTIATION: usize = 0;
const EDGE_SPLIT: usize = 1;
const EDGE_DUPLICATE: usize = 2;
const EDGE_SWAP: usize = 3;
const EDGE_GROW: usize = 4;
const EDGE_SHRINK: usize = 5;
const EDGE_TYPE: usize = 6;

impl Edge {
    fn transition_state(&mut self, network: &GeneNetwork) {
        // create an empty new state.
        let mut new_state = network.new_state();

        for (i, node) in network.nodes().iter().enumerate() {
            // determine the new state of ```node``` (position i in new_state)
            if node.sum_edges(&self.network_state) > 0 {
                // node is enabled
                new_state.state.insert(i);
            }
        }
        self.network_state = new_state;
    }

    fn develop(&mut self,
               network: &GeneNetwork,
               next_node_id: &mut usize,
               new_edges: &mut Vec<Edge>) {

        // first perform the state transition.
        self.transition_state(network);

        // perform the actions of all active nodes in the gene network.

        // first node is used for differentiation.
        // in a split/duplicate node, this will be set 0 or 1 in the children.
        // starting from second node, the nodes are mapped to graph grammar rules.

        if self.network_state.state.contains(EDGE_SPLIT) {
            let new_node = *next_node_id;
            *next_node_id += 1;

            // differentiate
            let mut child_state = self.network_state.clone();
            child_state.state.set(EDGE_DIFFERENTIATION,
                                  !self.network_state.state.contains(EDGE_DIFFERENTIATION));

            let new_edge = Edge {
                src_node: new_node,
                dst_node: self.dst_node,
                length: 0.5 * self.length,
                network_state: child_state,
                type_count: self.type_count, /* XXX: start with 0 or with the count of the current edge? */
            };
            self.dst_node = new_node;
            self.length /= 2.0;
            new_edges.push(new_edge);
        }

        if self.network_state.state.contains(EDGE_DUPLICATE) {
            // differentiate
            let mut child_state = self.network_state.clone();
            child_state.state.set(EDGE_DIFFERENTIATION,
                                  !self.network_state.state.contains(EDGE_DIFFERENTIATION));

            let new_edge = Edge {
                src_node: self.dst_node,
                dst_node: self.src_node,
                length: self.length,
                network_state: child_state,
                type_count: self.type_count, /* XXX: start with 0 or with the count of the current edge? */
            };
            new_edges.push(new_edge);
        }

        if self.network_state.state.contains(EDGE_SWAP) {
            mem::swap(&mut self.dst_node, &mut self.src_node);
        }

        if self.network_state.state.contains(EDGE_GROW) {
            self.length *= 1.25;
        }

        if self.network_state.state.contains(EDGE_SHRINK) {
            self.length *= 0.75;
        }

        if self.network_state.state.contains(EDGE_TYPE) {
            self.type_count += 1;
        }
    }
}

#[derive(Debug)]
struct GraphBuilder {
    edges: Vec<Edge>,
    next_node_id: usize,
    network: GeneNetwork,
}

impl GraphBuilder {
    fn new(network: GeneNetwork, zygote: GeneNetworkState) -> GraphBuilder {
        let initial_edge = Edge {
            src_node: 0,
            dst_node: 1,
            length: 1.0,
            type_count: 0,
            network_state: zygote,
        };

        GraphBuilder {
            edges: vec![initial_edge],
            next_node_id: 2,
            network: network,
        }
    }

    // During the process, some edges will be added (split), some others will be modified.
    fn next(&mut self) {
        let mut new_edges = Vec::new();
        for edge in self.edges.iter_mut() {
            edge.develop(&self.network, &mut self.next_node_id, &mut new_edges);
        }
        println!("next_node_id: {}", self.next_node_id);
        println!("new edges: {:?}", new_edges);
        self.edges.extend(new_edges);
    }

    fn write_dot<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        try!(writeln!(wr, "digraph artificial {{"));

        for edge in self.edges.iter() {
            try!(writeln!(wr,
                          "{} -> {} [weight={} label=\"{}\"]",
                          edge.src_node,
                          edge.dst_node,
                          edge.length,
                          edge.type_count));
        }

        try!(writeln!(wr, "}}"));

        Ok(())
    }
}

fn main() {
    use std::fs::File;
    // let genome = Genome::<Base4>::from_str("...11 _0320_23 <0101> T:0311 2...3 _1022_ 133 <0101> \
    // W:3213 121...")
    let mut rng = rand::thread_rng();

    let genome = Genome::<Base4>::random(&mut rng, 10 * 256);

    // let promoter = BaseString::<Base4>::from_str("0101").unwrap();
    let promoter = [B0, B1, B0, B1];

    let genes: Vec<_> = genome.iter_genes(&promoter, 4).collect();
    println!("{:?}", genes);

    let network = genome.construct_network(&promoter,
                                           4,
                                           &|product| {
                                               if product.last() == Some(&B0) {
                                                   // Inhibitor
                                                   ProteinRegulator::inhibit()
                                               } else {
                                                   // Inhibitor
                                                   ProteinRegulator::enhance()
                                               }
                                           });

    println!("{:#?}", network);

    let mut zygote = network.new_state();
    zygote.state.set(0, true);
    zygote.state.set(1, true);

    let mut gb = GraphBuilder::new(network, zygote);
    println!("{:#?}", gb);

    for i in 0..3 {
        gb.next();
    }
    println!("{:#?}", gb);

    gb.write_dot(&mut File::create("example1.dot").unwrap());

    // XXX: Convert each edge into a node and then connect these new nodes.
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate rocket;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_codegen;
extern crate dotenv;
extern crate serde_json;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate rocket_contrib;
#[macro_use]
extern crate serde_derive;
extern crate r2d2;
extern crate r2d2_diesel;

mod schema;
mod db;
mod note;
mod models;

use db::DB;
use note::{get_notes, create_note, delete_note, update_note};
use models::*;
use rocket_contrib::JSON;
use rocket::response::status::NoContent;
use diesel::result::Error;

#[get("/notes", format = "application/json")]
fn notes_get(db: DB) -> Result<JSON<Vec<Note>>, Error> {
    let notes = get_notes(db.conn());
    match notes {
        Ok(notes) => Ok(JSON(notes)),
        Err(err) => Err(err),
    }
}

#[post("/notes", format = "application/json", data = "<note>")]
fn note_create(db: DB, note: NoteData) -> Result<JSON<Note>, Error> {
    let created_note = create_note(db.conn(), note);
    match created_note {
        Ok(note) => Ok(JSON(note)),
        Err(err) => Err(err),
    }
}

#[patch("/notes/<id>", format = "application/json", data = "<note>")]
fn note_edit(db: DB, id: i32, note: NoteData) -> Result<JSON<Note>, Error> {
    let updated_note = update_note(db.conn(), id, note);
    match updated_note {
        Ok(note) => Ok(JSON(note)),
        Err(err) => Err(err),
    }
}

#[delete("/notes/<id>")]
fn note_delete(db: DB, id: i32) -> Result<NoContent, Error> {
    match delete_note(db.conn(), id) {
        Ok(_) => Ok(NoContent),
        Err(err) => Err(err),
    }
}

fn main() {
    rocket::ignite().mount("/", routes![note_create, notes_get, note_delete, note_edit]).launch();
}
<commit_msg>Added `/notes/<id>` route to get a single record<commit_after>#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate rocket;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_codegen;
extern crate dotenv;
extern crate serde_json;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate rocket_contrib;
#[macro_use]
extern crate serde_derive;
extern crate r2d2;
extern crate r2d2_diesel;

mod schema;
mod db;
mod note;
mod models;

use db::DB;
use note::{get_notes, get_note, create_note, delete_note, update_note};
use models::*;
use rocket_contrib::JSON;
use rocket::response::status::NoContent;
use diesel::result::Error;

#[get("/notes", format = "application/json")]
fn notes_get(db: DB) -> Result<JSON<Vec<Note>>, Error> {
    let notes = get_notes(db.conn());
    match notes {
        Ok(notes) => Ok(JSON(notes)),
        Err(err) => Err(err),
    }
}

#[get("/notes/<id>", format = "application/json")]
fn note_get(db: DB, id: i32) -> Result<JSON<Note>, Error> {
    let note = get_note(db.conn(), id);
    match note {
        Ok(note) => Ok(JSON(note)),
        Err(err) => Err(err),
    }
}

#[post("/notes", format = "application/json", data = "<note>")]
fn note_create(db: DB, note: NoteData) -> Result<JSON<Note>, Error> {
    let created_note = create_note(db.conn(), note);
    match created_note {
        Ok(note) => Ok(JSON(note)),
        Err(err) => Err(err),
    }
}

#[patch("/notes/<id>", format = "application/json", data = "<note>")]
fn note_edit(db: DB, id: i32, note: NoteData) -> Result<JSON<Note>, Error> {
    let updated_note = update_note(db.conn(), id, note);
    match updated_note {
        Ok(note) => Ok(JSON(note)),
        Err(err) => Err(err),
    }
}

#[delete("/notes/<id>")]
fn note_delete(db: DB, id: i32) -> Result<NoContent, Error> {
    match delete_note(db.conn(), id) {
        Ok(_) => Ok(NoContent),
        Err(err) => Err(err),
    }
}

fn main() {
    rocket::ignite().mount("/", routes![note_create, notes_get, note_delete, note_edit, note_get]).launch();
}
<|endoftext|>