<commit_before>extern crate syn;

use syn::{
    parse::{Parse, ParseStream},
    parse::discouraged::Speculative,
    Result,
};

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor() {
    struct Smuggled(ParseStream<'static>);
    impl Parse for Smuggled {
        fn parse(input: ParseStream) -> Result<Self> {
            Ok(Smuggled(unsafe { std::mem::transmute_copy(input) }))
        }
    }

    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let Smuggled(fork) = syn::parse_str("").unwrap();
            input.advance_to(fork);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("").unwrap();
}
<commit_msg>Add speculative smuggling test between bracket contexts<commit_after>#[macro_use]
extern crate syn;

use syn::{
    parse::{Parse, ParseStream},
    parse::discouraged::Speculative,
    Result,
};

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_sources() {
    // don't do this ever this is very unsafe and fails anyway
    struct Smuggled(ParseStream<'static>);
    impl Parse for Smuggled {
        fn parse(input: ParseStream) -> Result<Self> {
            Ok(Smuggled(unsafe { std::mem::transmute_copy(input) }))
        }
    }

    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let Smuggled(fork) = syn::parse_str("").unwrap();
            input.advance_to(fork);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("").unwrap();
}

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_brackets() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let a;
            let b;
            parenthesized!(a in input);
            parenthesized!(b in input);
            a.advance_to(&b);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("()()").unwrap();
}
<|endoftext|>


<commit_before>use criterion::Criterion;

use define_aho_corasick;
use input::*;

/// These benchmarks test various words on natural language text.
///
/// These benchmarks were mostly taken from the regex crate's benchmarks. For
/// example, the case insensitive benchmarks below are the result of generating
/// all possible case variants for a fixed prefix of each string.
pub fn all(c: &mut Criterion) {
    define_sherlock(c, "name/alt1", 158, vec!["Sherlock", "Street"]);
    define_sherlock(c, "name/alt2", 558, vec!["Sherlock", "Holmes"]);
    define_sherlock(
        c,
        "name/alt3",
        740,
        vec![
            "Sherlock", "Holmes", "Watson", "Irene", "Adler", "John", "Baker",
        ],
    );
    define_sherlock(c, "name/alt4", 582, vec!["Sher", "Hol"]);
    define_sherlock(c, "name/alt5", 639, vec!["Sherlock", "Holmes", "Watson"]);
    define_sherlock(
        c,
        "name/alt6",
        0,
        vec!["SherlockZ", "HolmesZ", "WatsonZ", "IreneZ", "MoriartyZ"],
    );
    define_sherlock(
        c,
        "name/alt7",
        0,
        vec!["Шерлок Холмс", "Джон Уотсон"],
    );

    define_sherlock(
        c,
        "name/nocase1",
        1764,
        vec![
            "ADL", "ADl", "AdL", "Adl", "BAK", "BAk", "BAK", "BaK", "Bak",
            "BaK", "HOL", "HOl", "HoL", "Hol", "IRE", "IRe", "IrE", "Ire",
            "JOH", "JOh", "JoH", "Joh", "SHE", "SHe", "ShE", "She", "WAT",
            "WAt", "WaT", "Wat", "aDL", "aDl", "adL", "adl", "bAK", "bAk",
            "bAK", "baK", "bak", "baK", "hOL", "hOl", "hoL", "hol", "iRE",
            "iRe", "irE", "ire", "jOH", "jOh", "joH", "joh", "sHE", "sHe",
            "shE", "she", "wAT", "wAt", "waT", "wat", "ſHE", "ſHe", "ſhE",
            "ſhe",
        ],
    );
    define_sherlock(
        c,
        "name/nocase2",
        1307,
        vec![
            "HOL", "HOl", "HoL", "Hol", "SHE", "SHe", "ShE", "She", "hOL",
            "hOl", "hoL", "hol", "sHE", "sHe", "shE", "she", "ſHE", "ſHe",
            "ſhE", "ſhe",
        ],
    );
    define_sherlock(
        c,
        "name/nocase3",
        1442,
        vec![
            "HOL", "HOl", "HoL", "Hol", "SHE", "SHe", "ShE", "She", "WAT",
            "WAt", "WaT", "Wat", "hOL", "hOl", "hoL", "hol", "sHE", "sHe",
            "shE", "she", "wAT", "wAt", "waT", "wat", "ſHE", "ſHe", "ſhE",
            "ſhe",
        ],
    );

    define_sherlock(c, "5000words", 567, words_5000());
}

fn define_sherlock<B: AsRef<[u8]>>(
    c: &mut Criterion,
    bench_name: &str,
    count: usize,
    patterns: Vec<B>,
) {
    define_aho_corasick(c, "sherlock", bench_name, SHERLOCK, count, patterns);
}
<commit_msg>style: new rustfmt changes<commit_after>use criterion::Criterion;

use define_aho_corasick;
use input::*;

/// These benchmarks test various words on natural language text.
///
/// These benchmarks were mostly taken from the regex crate's benchmarks. For
/// example, the case insensitive benchmarks below are the result of generating
/// all possible case variants for a fixed prefix of each string.
pub fn all(c: &mut Criterion) {
    define_sherlock(c, "name/alt1", 158, vec!["Sherlock", "Street"]);
    define_sherlock(c, "name/alt2", 558, vec!["Sherlock", "Holmes"]);
    define_sherlock(
        c,
        "name/alt3",
        740,
        vec![
            "Sherlock", "Holmes", "Watson", "Irene", "Adler", "John", "Baker",
        ],
    );
    define_sherlock(c, "name/alt4", 582, vec!["Sher", "Hol"]);
    define_sherlock(c, "name/alt5", 639, vec!["Sherlock", "Holmes", "Watson"]);
    define_sherlock(
        c,
        "name/alt6",
        0,
        vec!["SherlockZ", "HolmesZ", "WatsonZ", "IreneZ", "MoriartyZ"],
    );
    define_sherlock(c, "name/alt7", 0, vec!["Шерлок Холмс", "Джон Уотсон"]);

    define_sherlock(
        c,
        "name/nocase1",
        1764,
        vec![
            "ADL", "ADl", "AdL", "Adl", "BAK", "BAk", "BAK", "BaK", "Bak",
            "BaK", "HOL", "HOl", "HoL", "Hol", "IRE", "IRe", "IrE", "Ire",
            "JOH", "JOh", "JoH", "Joh", "SHE", "SHe", "ShE", "She", "WAT",
            "WAt", "WaT", "Wat", "aDL", "aDl", "adL", "adl", "bAK", "bAk",
            "bAK", "baK", "bak", "baK", "hOL", "hOl", "hoL", "hol", "iRE",
            "iRe", "irE", "ire", "jOH", "jOh", "joH", "joh", "sHE", "sHe",
            "shE", "she", "wAT", "wAt", "waT", "wat", "ſHE", "ſHe", "ſhE",
            "ſhe",
        ],
    );
    define_sherlock(
        c,
        "name/nocase2",
        1307,
        vec![
            "HOL", "HOl", "HoL", "Hol", "SHE", "SHe", "ShE", "She", "hOL",
            "hOl", "hoL", "hol", "sHE", "sHe", "shE", "she", "ſHE", "ſHe",
            "ſhE", "ſhe",
        ],
    );
    define_sherlock(
        c,
        "name/nocase3",
        1442,
        vec![
            "HOL", "HOl", "HoL", "Hol", "SHE", "SHe", "ShE", "She", "WAT",
            "WAt", "WaT", "Wat", "hOL", "hOl", "hoL", "hol", "sHE", "sHe",
            "shE", "she", "wAT", "wAt", "waT", "wat", "ſHE", "ſHe", "ſhE",
            "ſhe",
        ],
    );

    define_sherlock(c, "5000words", 567, words_5000());
}

fn define_sherlock<B: AsRef<[u8]>>(
    c: &mut Criterion,
    bench_name: &str,
    count: usize,
    patterns: Vec<B>,
) {
    define_aho_corasick(c, "sherlock", bench_name, SHERLOCK, count, patterns);
}
<|endoftext|>


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

extern crate cmake;

use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

static SHADERC_REPO: &'static str = "https://github.com/google/shaderc";
static GLSLANG_REPO: &'static str = "https://github.com/google/glslang";
static SPIRV_TOOLS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Tools";
static SPIRV_HEADERS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Headers";

// Updated on 2017-09-30
static SHADERC_COMMIT: &'static str = "c8ba3e4694ff554f95000ec35e6e55f2ba637fb3";
static GLSLANG_COMMIT: &'static str = "44dd6a00c388ba09f7ac64a3921b4717a89f949c";
static SPIRV_TOOLS_COMMIT: &'static str = "17a843c6b0ac39edce3ca45246b78c8f47c7ebee";
static SPIRV_HEADERS_COMMIT: &'static str = "77240d9e86c6ff135f6de8c7b89a0099a2d90e16";

fn git_clone_or_update(project: &str, url: &str, commit: &str, dir: &PathBuf) {
    if dir.as_path().exists() {
        let status = Command::new("git")
            .arg("pull")
            .current_dir(dir)
            .status()
            .expect("failed to execute git pull");
        if !status.success() {
            panic!("git pull {} failed", project)
        }
    } else {
        let status = Command::new("git")
            .args(&["clone", url, dir.to_str().unwrap()])
            .status()
            .expect("failed to execute git clone");
        if !status.success() {
            panic!("git clone {} failed", project)
        }
    }

    let status = Command::new("git")
        .args(&["checkout", commit])
        .current_dir(dir)
        .status()
        .expect("failed to execute git checkout");
    if !status.success() {
        panic!("git checkout {} failed", commit)
    }
}

fn build_shaderc(shaderc_dir: &PathBuf) -> PathBuf {
        cmake::Config::new(shaderc_dir)
            .profile("Release")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .define("SPIRV_SKIP_EXECUTABLES", "ON")
            .define("SHADERC_SKIP_TESTS", "ON")
            .build()
}

fn main() {
    if env::var("CARGO_FEATURE_BUILD_NATIVE_SHADERC").is_err() {
        println!("cargo:warning=requested to skip building native C++ shaderc");
        return
    }

    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let target_dir = Path::new(&manifest_dir).join("target");
    let shaderc_dir = Path::new(&target_dir).join("native-shaderc");
    let third_party_dir = Path::new(&shaderc_dir).join("third_party");
    let glslang_dir = Path::new(&third_party_dir).join("glslang");
    let spirv_tools_dir = Path::new(&third_party_dir).join("spirv-tools");
    let external_dir = Path::new(&spirv_tools_dir).join("external");
    let spirv_headers_dir = Path::new(&external_dir).join("spirv-headers");

    git_clone_or_update("shaderc", SHADERC_REPO, SHADERC_COMMIT, &shaderc_dir);
    git_clone_or_update("glslang", GLSLANG_REPO, GLSLANG_COMMIT, &glslang_dir);
    git_clone_or_update("spirv-tools", SPIRV_TOOLS_REPO, SPIRV_TOOLS_COMMIT, &spirv_tools_dir);
    git_clone_or_update("spirv-headers", SPIRV_HEADERS_REPO, SPIRV_HEADERS_COMMIT, &spirv_headers_dir);

    let mut lib_path = build_shaderc(&shaderc_dir);
    lib_path.push("lib");

    println!("cargo:rustc-link-lib=static=shaderc_combined");
    println!("cargo:rustc-link-search=native={}", lib_path.display());
}
<commit_msg>Add MSVC-specific CMake options back in<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate cmake;

use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

static SHADERC_REPO: &'static str = "https://github.com/google/shaderc";
static GLSLANG_REPO: &'static str = "https://github.com/google/glslang";
static SPIRV_TOOLS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Tools";
static SPIRV_HEADERS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Headers";

// Updated on 2017-09-30
static SHADERC_COMMIT: &'static str = "c8ba3e4694ff554f95000ec35e6e55f2ba637fb3";
static GLSLANG_COMMIT: &'static str = "44dd6a00c388ba09f7ac64a3921b4717a89f949c";
static SPIRV_TOOLS_COMMIT: &'static str = "17a843c6b0ac39edce3ca45246b78c8f47c7ebee";
static SPIRV_HEADERS_COMMIT: &'static str = "77240d9e86c6ff135f6de8c7b89a0099a2d90e16";

fn git_clone_or_update(project: &str, url: &str, commit: &str, dir: &PathBuf) {
    if dir.as_path().exists() {
        let status = Command::new("git")
            .arg("pull")
            .current_dir(dir)
            .status()
            .expect("failed to execute git pull");
        if !status.success() {
            panic!("git pull {} failed", project)
        }
    } else {
        let status = Command::new("git")
            .args(&["clone", url, dir.to_str().unwrap()])
            .status()
            .expect("failed to execute git clone");
        if !status.success() {
            panic!("git clone {} failed", project)
        }
    }

    let status = Command::new("git")
        .args(&["checkout", commit])
        .current_dir(dir)
        .status()
        .expect("failed to execute git checkout");
    if !status.success() {
        panic!("git checkout {} failed", commit)
    }
}

fn build_shaderc(shaderc_dir: &PathBuf) -> PathBuf {
        cmake::Config::new(shaderc_dir)
            .profile("Release")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .define("SPIRV_SKIP_EXECUTABLES", "ON")
            .define("SHADERC_SKIP_TESTS", "ON")
            .build()
}

fn build_shaderc_msvc(shaderc_dir: &PathBuf) -> PathBuf {
    cmake::Config::new(shaderc_dir)
            .profile("Release")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .define("SPIRV_SKIP_EXECUTABLES", "ON")
            .define("SHADERC_SKIP_TESTS", "ON")
            // cmake-rs tries to be clever on Windows by injecting several
            // C/C++ flags, which causes problems. So I have to manually
            // define CMAKE_*_FLAGS_* here to suppress that.
            .define("CMAKE_C_FLAGS", " /nologo /EHsc")
            .define("CMAKE_CXX_FLAGS", " /nologo /EHsc")
            .define("CMAKE_C_FLAGS_RELEASE", " /nologo /EHsc")
            .define("CMAKE_CXX_FLAGS_RELEASE", " /nologo /EHsc")
            .build()
}

fn main() {
    if env::var("CARGO_FEATURE_BUILD_NATIVE_SHADERC").is_err() {
        println!("cargo:warning=requested to skip building native C++ shaderc");
        return
    }
    let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let target_dir = Path::new(&manifest_dir).join("target");
    let shaderc_dir = Path::new(&target_dir).join("native-shaderc");
    let third_party_dir = Path::new(&shaderc_dir).join("third_party");
    let glslang_dir = Path::new(&third_party_dir).join("glslang");
    let spirv_tools_dir = Path::new(&third_party_dir).join("spirv-tools");
    let external_dir = Path::new(&spirv_tools_dir).join("external");
    let spirv_headers_dir = Path::new(&external_dir).join("spirv-headers");

    git_clone_or_update("shaderc", SHADERC_REPO, SHADERC_COMMIT, &shaderc_dir);
    git_clone_or_update("glslang", GLSLANG_REPO, GLSLANG_COMMIT, &glslang_dir);
    git_clone_or_update("spirv-tools", SPIRV_TOOLS_REPO, SPIRV_TOOLS_COMMIT, &spirv_tools_dir);
    git_clone_or_update("spirv-headers", SPIRV_HEADERS_REPO, SPIRV_HEADERS_COMMIT, &spirv_headers_dir);

    let mut lib_path = if target_env == "msvc" {
        build_shaderc_msvc(&shaderc_dir)
    } else {
        build_shaderc(&shaderc_dir)
    };

    lib_path.push("lib");

    println!("cargo:rustc-link-lib=static=shaderc_combined");
    println!("cargo:rustc-link-search=native={}", lib_path.display());
}
<|endoftext|>


<commit_before>use super::Position;
use super::Range;
use std::str::from_utf8;

pub struct GapBuffer {
    data: Vec<u8>,
    gap_start: usize,
    gap_length: usize,
}

pub fn new(mut data: String) -> GapBuffer {
    let mut bytes = data.into_bytes();
    let capacity = bytes.capacity();
    let gap_start = bytes.len();
    let gap_length = capacity - gap_start;
    unsafe {
        bytes.set_len(capacity);
    }
    GapBuffer{ data: bytes, gap_start: gap_start, gap_length: gap_length }
}

impl GapBuffer {
    // TODO: Return an optional error.
    pub fn insert(&mut self, data: &str, position: &Position) {
        // Ensure we have the capacity to insert this data.
        if data.len() > self.gap_length {
            // TODO: Move gap to the end before resizing buffer.
            self.data.reserve(data.len());
            let capacity = self.data.capacity();
            self.gap_length = capacity - self.gap_start;
            unsafe {
                self.data.set_len(capacity);
            }
        }

        let offset = match self.find_offset(position) {
            Some(o) => o,
            None => return,
        };

        self.move_gap(offset);
        self.write_to_gap(data);
    }

    pub fn to_string(&self) -> String {
        from_utf8(&self.data[..self.gap_start]).unwrap().to_string() + from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap()
    }

    // Maps a position to its offset equivalent in the data.
    fn find_offset(&self, position: &Position) -> Option<usize> {
        let first_half = from_utf8(&self.data[..self.gap_start]).unwrap();
        let mut line = 0;
        let mut line_offset = 0;

        for char_index in first_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We didn't find the position *within* the first half, but it could
        // be right after it, which means it's right at the start of the gap.
        if line == position.line && line_offset == position.offset {
            return Some(self.gap_start);
        }

        // We haven't reached the position yet, so we'll move on to the other half.
        let second_half = from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap();
        for char_index in second_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(self.gap_start + self.gap_length + offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        None
    }

    fn move_gap(&mut self, offset: usize) {
        if offset < self.gap_start {
            for index in (offset..self.gap_start) {
                self.data[index + self.gap_length] = self.data[index];
                self.data[index] = 0;
            }
        } else if offset > self.gap_start {
            for index in (self.gap_start+self.gap_length..offset) {
                self.data[index-self.gap_length] = self.data[index];
                self.data[index] = 0;
            }
        }

        self.gap_start = offset;
    }

    fn write_to_gap(&mut self, data: &str) {
        for byte in data.bytes() {
            self.data[self.gap_start] = byte;
            self.gap_start+=1;
            self.gap_length-=1;
        }
    }
}

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

    #[test]
    fn inserting_at_the_start_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert("Hi. ", &Position { line: 0, offset: 0 });
        assert_eq!(gb.to_string(), "Hi. This is a test.");
    }

    #[test]
    fn inserting_in_the_middle_works() {
        let mut gb = new("This is a test.\nPlease be gentle.".to_string());
        gb.insert(" very", &Position { line: 1, offset: 9 });
        assert_eq!(gb.to_string(), "This is a test.\nPlease be very gentle.");
    }

    #[test]
    fn inserting_at_the_end_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert(" Seriously.", &Position { line: 0, offset: 15 });
        assert_eq!(gb.to_string(), "This is a test. Seriously.");
    }
}
<commit_msg>Update insert to handle subsequent calls at different locations.<commit_after>use super::Position;
use super::Range;
use std::str::from_utf8;

pub struct GapBuffer {
    data: Vec<u8>,
    gap_start: usize,
    gap_length: usize,
}

pub fn new(mut data: String) -> GapBuffer {
    let mut bytes = data.into_bytes();
    let capacity = bytes.capacity();
    let gap_start = bytes.len();
    let gap_length = capacity - gap_start;
    unsafe {
        bytes.set_len(capacity);
    }
    GapBuffer{ data: bytes, gap_start: gap_start, gap_length: gap_length }
}

impl GapBuffer {
    // TODO: Return an optional error.
    pub fn insert(&mut self, data: &str, position: &Position) {
        // Ensure we have the capacity to insert this data.
        if data.len() > self.gap_length {
            // TODO: Move gap to the end before resizing buffer.
            self.data.reserve(data.len());
            let capacity = self.data.capacity();
            self.gap_length = capacity - self.gap_start;
            unsafe {
                self.data.set_len(capacity);
            }
        }

        let offset = match self.find_offset(position) {
            Some(o) => o,
            None => return,
        };

        self.move_gap(offset);
        self.write_to_gap(data);
    }

    pub fn to_string(&self) -> String {
        from_utf8(&self.data[..self.gap_start]).unwrap().to_string() + from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap()
    }

    // Maps a position to its offset equivalent in the data.
    fn find_offset(&self, position: &Position) -> Option<usize> {
        let first_half = from_utf8(&self.data[..self.gap_start]).unwrap();
        let mut line = 0;
        let mut line_offset = 0;

        for char_index in first_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We didn't find the position *within* the first half, but it could
        // be right after it, which means it's right at the start of the gap.
        if line == position.line && line_offset == position.offset {
            return Some(self.gap_start);
        }

        // We haven't reached the position yet, so we'll move on to the other half.
        let second_half = from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap();
        for char_index in second_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(self.gap_start + self.gap_length + offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We didn't find the position *within* the second half, but it could
        // be right after it, which means it's at the end of the buffer.
        if line == position.line && line_offset == position.offset {
            return Some(self.data.len());
        }

        None
    }

    fn move_gap(&mut self, offset: usize) {
        if offset < self.gap_start {
            // Shift the gap to the left one byte at a time.
            for index in (offset..self.gap_start) {
                self.data[index + self.gap_length] = self.data[index];
                self.data[index] = 0;
            }

            self.gap_start = offset;
        } else if offset > self.gap_start {
            // Shift the gap to the right one byte at a time.
            for index in (self.gap_start+self.gap_length..offset) {
                self.data[index-self.gap_length] = self.data[index];
                self.data[index] = 0;
            }

            // Because the offset was after the gap, its value included the
            // gap length. We must remove it to determine the starting point.
            self.gap_start = offset - self.gap_length;
        }
    }

    fn write_to_gap(&mut self, data: &str) {
        for byte in data.bytes() {
            self.data[self.gap_start] = byte;
            self.gap_start+=1;
            self.gap_length-=1;
        }
    }
}

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

    #[test]
    fn inserting_at_the_start_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert("Hi. ", &Position { line: 0, offset: 0 });
        assert_eq!(gb.to_string(), "Hi. This is a test.");
    }

    #[test]
    fn inserting_in_the_middle_works() {
        let mut gb = new("This is a test.\nPlease be gentle.".to_string());
        gb.insert(" very", &Position { line: 1, offset: 9 });
        assert_eq!(gb.to_string(), "This is a test.\nPlease be very gentle.");
    }

    #[test]
    fn inserting_at_the_end_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert(" Seriously.", &Position { line: 0, offset: 15 });
        assert_eq!(gb.to_string(), "This is a test. Seriously.");
    }

    #[test]
    fn inserting_in_different_spots_twice_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert("Hi. ", &Position { line: 0, offset: 0 });
        gb.insert(" Thank you.", &Position { line: 0, offset: 19 });
        assert_eq!(gb.to_string(), "Hi. This is a test. Thank you.");
    }
}
<|endoftext|>


<commit_before>use crate::interchange_gen::routing_graph::*;
use crate::schema::*;
use crate::chip::Chip;
use crate::database::Database;
use crate::bba::idstring::*;

use std::convert::TryInto;

use flate2::Compression;
use flate2::write::GzEncoder;

pub fn write(c: &Chip, _db: &mut Database, ids: &mut IdStringDB, graph: &IcGraph, filename: &str) -> ::capnp::Result<()> {
    let mut m = ::capnp::message::Builder::new_default();
    {
        let mut dev = m.init_root::<DeviceResources_capnp::device::Builder>();
        dev.set_name(&c.device);
        {
            let mut tiletypes = dev.reborrow().init_tile_type_list(graph.tile_types.len().try_into().unwrap());
            for (i, (_, data)) in graph.tile_types.iter().enumerate() {
                let mut tt = tiletypes.reborrow().get(i.try_into().unwrap());
                // TODO: form a nice name from the constituent tile types
                tt.set_name(ids.id(&format!("tiletype_{}", i)).val().try_into().unwrap());
                {
                    let mut wires = tt.reborrow().init_wires(data.wires.len().try_into().unwrap());
                    for (j, (_, wire_data)) in data.wires.iter().enumerate() {
                        wires.set(j.try_into().unwrap(),  wire_data.name.val().try_into().unwrap());
                    }
                }
                {
                    let mut pips = tt.reborrow().init_pips(data.pips.len().try_into().unwrap());
                    for (j, pip_data) in data.pips.iter().enumerate() {
                        let mut p = pips.reborrow().get(j.try_into().unwrap());
                        p.set_wire0(pip_data.src_wire.try_into().unwrap());
                        p.set_wire1(pip_data.dst_wire.try_into().unwrap());
                        p.set_directional(true);
                        p.set_buffered20(true);
                        p.set_buffered21(false);
                        p.set_conventional(());
                    }
                }
                // TODO: constant sources
            }
        }
        let mut wire_list = Vec::new();
        {
            // this wire_list is the list of wires as we create nodes, to be output as dev.wires later
            let mut nodes = dev.reborrow().init_nodes(graph.nodes.len().try_into().unwrap());
            for (i, node_data) in graph.nodes.iter().enumerate() {
                let n = nodes.reborrow().get(i.try_into().unwrap());
                let mut node_wires = n.init_wires(node_data.wires.len().try_into().unwrap());
                // write root wire
                {
                    node_wires.set(0, wire_list.len().try_into().unwrap());
                    wire_list.push((node_data.root_wire.tile_idx, node_data.root_wire.wire_idx));
                }
                let mut node_wire_idx = 1;
                // write non-root wires
                for wire in node_data.wires.iter().filter(|w| **w != node_data.root_wire) {
                    node_wires.set(node_wire_idx, wire_list.len().try_into().unwrap());
                    wire_list.push((wire.tile_idx, wire.wire_idx));
                    node_wire_idx += 1;
                }
            }
        }
        {
            let mut wires = dev.reborrow().init_wires(wire_list.len().try_into().unwrap());
            for (i, (tile_idx, wire_idx)) in wire_list.iter().enumerate() {
                let mut w = wires.reborrow().get(i.try_into().unwrap());
                // TODO: should IcGraph use IdStrings to better match what we write out?
                let tile = &graph.tiles[*tile_idx];
                w.set_tile(tile.name.val().try_into().unwrap());
                w.set_wire(graph.tile_types.value(tile.type_idx).wires.value(*wire_idx).name.val().try_into().unwrap());
            }
        }
        {
            let mut strs = dev.init_str_list(ids.len().try_into().unwrap());
            for i in 0..ids.len() {
                strs.set(i.try_into().unwrap(), ids.idx_str(i));
            }
        }
    }
    let mut e = GzEncoder::new(std::fs::File::create(filename)?, Compression::default());
    ::capnp::serialize::write_message(&mut e, &m)?;
    e.finish()?;
    Ok(())
}
<commit_msg>interchange: Add tiles and const cells<commit_after>use crate::interchange_gen::routing_graph::*;
use crate::schema::*;
use crate::chip::Chip;
use crate::database::Database;
use crate::bba::idstring::*;

use std::convert::TryInto;

use flate2::Compression;
use flate2::write::GzEncoder;

pub fn write(c: &Chip, _db: &mut Database, ids: &mut IdStringDB, graph: &IcGraph, filename: &str) -> ::capnp::Result<()> {
    let mut m = ::capnp::message::Builder::new_default();
    {
        let mut dev = m.init_root::<DeviceResources_capnp::device::Builder>();
        dev.set_name(&c.device);
        {
            let mut tiletypes = dev.reborrow().init_tile_type_list(graph.tile_types.len().try_into().unwrap());
            for (i, (_, data)) in graph.tile_types.iter().enumerate() {
                let mut tt = tiletypes.reborrow().get(i.try_into().unwrap());
                // TODO: form a nice name from the constituent tile types
                tt.set_name(ids.id(&format!("tiletype_{}", i)).val().try_into().unwrap());
                {
                    let mut wires = tt.reborrow().init_wires(data.wires.len().try_into().unwrap());
                    for (j, (_, wire_data)) in data.wires.iter().enumerate() {
                        wires.set(j.try_into().unwrap(),  wire_data.name.val().try_into().unwrap());
                    }
                }
                {
                    let mut pips = tt.reborrow().init_pips(data.pips.len().try_into().unwrap());
                    for (j, pip_data) in data.pips.iter().enumerate() {
                        let mut p = pips.reborrow().get(j.try_into().unwrap());
                        p.set_wire0(pip_data.src_wire.try_into().unwrap());
                        p.set_wire1(pip_data.dst_wire.try_into().unwrap());
                        p.set_directional(true);
                        p.set_buffered20(true);
                        p.set_buffered21(false);
                        p.set_conventional(());
                    }
                }
                // TODO: constant sources
            }
        }
        let mut wire_list = Vec::new();
        {
            // this wire_list is the list of wires as we create nodes, to be output as dev.wires later
            let mut nodes = dev.reborrow().init_nodes(graph.nodes.len().try_into().unwrap());
            for (i, node_data) in graph.nodes.iter().enumerate() {
                let n = nodes.reborrow().get(i.try_into().unwrap());
                let mut node_wires = n.init_wires(node_data.wires.len().try_into().unwrap());
                // write root wire
                {
                    node_wires.set(0, wire_list.len().try_into().unwrap());
                    wire_list.push((node_data.root_wire.tile_idx, node_data.root_wire.wire_idx));
                }
                let mut node_wire_idx = 1;
                // write non-root wires
                for wire in node_data.wires.iter().filter(|w| **w != node_data.root_wire) {
                    node_wires.set(node_wire_idx, wire_list.len().try_into().unwrap());
                    wire_list.push((wire.tile_idx, wire.wire_idx));
                    node_wire_idx += 1;
                }
            }
        }
        {
            let mut wires = dev.reborrow().init_wires(wire_list.len().try_into().unwrap());
            for (i, (tile_idx, wire_idx)) in wire_list.iter().enumerate() {
                let mut w = wires.reborrow().get(i.try_into().unwrap());
                // TODO: should IcGraph use IdStrings to better match what we write out?
                let tile = &graph.tiles[*tile_idx];
                w.set_tile(tile.name.val().try_into().unwrap());
                w.set_wire(graph.tile_types.value(tile.type_idx).wires.value(*wire_idx).name.val().try_into().unwrap());
            }
        }
        {
            let mut tiles = dev.reborrow().init_tile_list(graph.tiles.len().try_into().unwrap());
            for (i, tile_data) in graph.tiles.iter().enumerate() {
                let mut t = tiles.reborrow().get(i.try_into().unwrap());
                t.set_name(tile_data.name.val().try_into().unwrap());
                t.set_type(tile_data.type_idx.try_into().unwrap());
                t.set_row(tile_data.y.try_into().unwrap());
                t.set_col(tile_data.x.try_into().unwrap());
            }
        }
        {
            let mut constants = dev.reborrow().init_constants();
            constants.set_gnd_cell_type(ids.id("VLO").val().try_into().unwrap());
            constants.set_gnd_cell_pin(ids.id("Z").val().try_into().unwrap());
            constants.set_vcc_cell_type(ids.id("VHI").val().try_into().unwrap());
            constants.set_vcc_cell_pin(ids.id("Z").val().try_into().unwrap());
        }
        {
            let mut c2b = dev.reborrow().init_cell_bel_map(2);
            c2b.reborrow().get(0).set_cell(ids.id("VLO").val().try_into().unwrap());
            c2b.reborrow().get(1).set_cell(ids.id("VHI").val().try_into().unwrap());
        }
        {
            let mut strs = dev.init_str_list(ids.len().try_into().unwrap());
            for i in 0..ids.len() {
                strs.set(i.try_into().unwrap(), ids.idx_str(i));
            }
        }
    }
    let mut e = GzEncoder::new(std::fs::File::create(filename)?, Compression::default());
    ::capnp::serialize::write_message(&mut e, &m)?;
    e.finish()?;
    Ok(())
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod opcode_test
{
    extern crate csv;
    extern crate hex;

    use self::hex::FromHex;
    use system::*;
    use cpu::opcode::*;
    use std::env;
    use std::error::Error;
    use std::ffi::OsString;
    use std::fs::File;
    use std::process;

    #[test]
    fn increments_propper_register()
    {

        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        //A
        let opcode = 0x3C;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.accumulator, 1);
        //B
        registers.program_counter -= 1;
        let opcode = 0x04;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.b_register, 1);
        //C
        registers.program_counter -= 1;
        let opcode = 0x0C;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.c_register, 1);
        //D
        registers.program_counter -= 1;
        let opcode = 0x14;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.d_register, 1);
        //E
        registers.program_counter -= 1;
        let opcode = 0x1C;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.e_register, 1);
        //H
        registers.program_counter -= 1;
        let opcode = 0x24;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.h_register, 1);
        //L
        registers.program_counter -= 1;
        let opcode = 0x2C;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.l_register, 1);
    }

    #[test]
    fn loads_n_to_correct_register_8_bit()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        system_data.mem_map[1] = 1;
        //A
        let opcode = 0x3E;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.accumulator, 1);
        //B
        registers.program_counter -= 2;
        let opcode = 0x06;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.b_register, 1);
        //C
        registers.program_counter -= 2;
        let opcode = 0x0E;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.c_register, 1);
        //D
        registers.program_counter -= 2;
        let opcode = 0x16;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.d_register, 1);
        //E
        registers.program_counter -= 2;
        let opcode = 0x1E;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.e_register, 1);
        //H
        registers.program_counter -= 2;
        let opcode = 0x26;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.h_register, 1);
        //L
        registers.program_counter -= 2;
        let opcode = 0x2E;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.l_register, 1);
    }

    #[test]
    fn accumulator_io_load_with_c_offset()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        registers.accumulator = 1;
        registers.c_register = 1;
        load_accumulator_to_io_port_with_c_offset(&mut system_data, &mut registers);
        assert_eq!(system_data.mem_map[0xFF01], 1);
    }

    #[test]
    fn loads_nn_to_correct_register_16_bit()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        system_data.mem_map[1] = 0x01;
        system_data.mem_map[2] = 0x02;
        //bc
        let opcode = 0x01;
        load_nn_to_16bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.b_register, 2);
        assert_eq!(registers.c_register, 1);
        //de
        registers.program_counter -= 3;
        let opcode = 0x11;
        load_nn_to_16bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.d_register, 2);
        assert_eq!(registers.e_register, 1);
        //hl
        registers.program_counter -= 3;
        let opcode = 0x21;
        load_nn_to_16bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.h_register, 2);
        assert_eq!(registers.l_register, 1);
        //stack pointer
        registers.program_counter -= 3;
        let opcode = 0x31;
        load_nn_to_16bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.stack_pointer, 0x0201);

    }

    #[test]
    fn xor_register_test()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        let opcode = 0xAF;
        //A
        registers.accumulator = 0xFF;
        xor_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.accumulator, 0);
    }

    #[test]
    fn pc_jumps_displacement_on_nonzero_flag()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        registers.program_counter = 100;
        //Positive Jump
        system_data.mem_map[101] = 10;
        registers.flags = 0x00;
        jump_displacement_on_nonzero_flag(&mut system_data, &mut registers);
        assert_eq!(registers.program_counter, 112);
        //Negative Jump
        registers.program_counter = 100;
        system_data.mem_map[101] = 253;
        registers.flags = 0x00;
        jump_displacement_on_nonzero_flag(&mut system_data, &mut registers);
        assert_eq!(registers.program_counter, 99);
        //Zero Flag
        registers.program_counter = 100;
        system_data.mem_map[101] = 0xFF;
        registers.flags = 0xFF;
        jump_displacement_on_nonzero_flag(&mut system_data, &mut registers);
        assert_eq!(registers.program_counter, 102)
    }

    #[test]
    fn load_decrement_hl_register_location_with_accumulator_test()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        //Normal increment
        registers.h_register = 0xFF;
        registers.l_register = 0xFF;
        registers.accumulator = 1;
        load_decrement_hl_register_location_with_accumulator(&mut system_data, &mut registers);
        assert_eq!(system_data.mem_map[0xFFFF], 1);
        assert_eq!(registers.h_register, 0xFF);
        assert_eq!(registers.l_register, 0xFE);
    }

    #[test]
    fn bit_check_register_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        //H
        //Zero Flag
        let opcode = 0x7C;
        let test_bit = 7;
        registers.h_register = 0x00;
        bit_check_register(&mut system_data, &mut registers, opcode, test_bit);
        assert_eq!(registers.flags, 0xA0);
        //No Zero Flag
        let opcode = 0x7C;
        let test_bit = 7;
        registers.h_register = 0xFF;
        bit_check_register(&mut system_data, &mut registers, opcode, test_bit);
        assert_eq!(registers.flags, 0x20);
    }

    #[test]
    fn load_hl_address_with_register_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        registers.h_register = 0xFF;
        registers.l_register = 0xFF;
        registers.accumulator = 1;
        registers.b_register = 2;
        registers.c_register = 3;
        registers.d_register = 4;
        registers.e_register = 5;

        //A
        let opcode = 0x77;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 1);
        //B
        let opcode = 0x70;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 2);
        //C
        let opcode = 0x71;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 3);
        //D
        let opcode = 0x72;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 4);
        //E
        let opcode = 0x73;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 5);
        //H
        let opcode = 0x74;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 0xFF);
        //L
        let opcode = 0x75;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 0xFF);
    }

    #[test]
    fn load_accumulator_to_io_port_with_a_offset_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        registers.accumulator = 1;
        system_data.mem_map[1] = 1;
        load_accumulator_to_io_port_with_n_offset(&mut system_data, &mut registers);
        assert_eq!(system_data.mem_map[0xFF01], 1);
    }

    #[test]
    fn load_8_bit_register_to_register_test()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        let asserts = File::open("src/cpu/ld_r_r_asserts.csv").unwrap();
        let mut rdr_asserts = csv::ReaderBuilder::new()
            .has_headers(false)
            .from_reader(asserts);
        let opcodes = File::open("src/cpu/ld_r_r_opcodes.csv").unwrap();
        let mut rdr_opcodes = csv::ReaderBuilder::new()
            .has_headers(false)
            .from_reader(opcodes);
        let mut asserts: Vec<String> = Vec::new();
        let mut opcodes: Vec<String> = Vec::new();
        for record in rdr_asserts.records()
        {
            asserts.push(String::from(&(record.unwrap())[0]));
        }
        for record in rdr_opcodes.records()
        {
            opcodes.push(String::from(&(record.unwrap())[0]));
        }

        let mut count : u8 = 0;
        for index in 0..asserts.len()
        {
            if(index % 7 == 0){
                for i in 0..7
                {
                    registers.mapped_register_setter(i, i + 1)
                }
                if index > 0
                {
                    count += 1;
                }
            }
            let opcode = Vec::from_hex(&opcodes[index]).unwrap();
            load_8_bit_register_to_register(&mut system_data, &mut registers, opcode[0]);
            assert_eq!(asserts[index].parse::<u8>().unwrap(), registers.mapped_register_getter(count));
        }
    }

    #[test]
    fn load_accumulator_with_de_address_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        registers.d_register = 0xFF;
        registers.e_register = 0xEE;
        system_data.mem_map[0xFFEE] = 1;
        load_accumulator_with_de_address(&mut system_data, &mut registers);
        assert_eq!(registers.accumulator, 1);
    }

    // #[test]
    // fn call_nn_test() {
    //     unimplemented!();
    // }
}<commit_msg>slight shortening<commit_after>#[cfg(test)]
mod opcode_test
{
    extern crate csv;
    extern crate hex;

    use self::hex::FromHex;
    use system::*;
    use cpu::opcode::*;
    use std::env;
    use std::error::Error;
    use std::ffi::OsString;
    use std::fs::File;
    use std::process;

    #[test]
    fn increments_propper_register()
    {

        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        //A
        let opcode = 0x3C;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.accumulator, 1);
        //B
        registers.program_counter -= 1;
        let opcode = 0x04;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.b_register, 1);
        //C
        registers.program_counter -= 1;
        let opcode = 0x0C;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.c_register, 1);
        //D
        registers.program_counter -= 1;
        let opcode = 0x14;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.d_register, 1);
        //E
        registers.program_counter -= 1;
        let opcode = 0x1C;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.e_register, 1);
        //H
        registers.program_counter -= 1;
        let opcode = 0x24;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.h_register, 1);
        //L
        registers.program_counter -= 1;
        let opcode = 0x2C;
        increment(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.l_register, 1);
    }

    #[test]
    fn loads_n_to_correct_register_8_bit()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        system_data.mem_map[1] = 1;
        //A
        let opcode = 0x3E;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.accumulator, 1);
        //B
        registers.program_counter -= 2;
        let opcode = 0x06;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.b_register, 1);
        //C
        registers.program_counter -= 2;
        let opcode = 0x0E;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.c_register, 1);
        //D
        registers.program_counter -= 2;
        let opcode = 0x16;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.d_register, 1);
        //E
        registers.program_counter -= 2;
        let opcode = 0x1E;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.e_register, 1);
        //H
        registers.program_counter -= 2;
        let opcode = 0x26;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.h_register, 1);
        //L
        registers.program_counter -= 2;
        let opcode = 0x2E;
        load_n_to_8bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.l_register, 1);
    }

    #[test]
    fn accumulator_io_load_with_c_offset()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        registers.accumulator = 1;
        registers.c_register = 1;
        load_accumulator_to_io_port_with_c_offset(&mut system_data, &mut registers);
        assert_eq!(system_data.mem_map[0xFF01], 1);
    }

    #[test]
    fn loads_nn_to_correct_register_16_bit()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        system_data.mem_map[1] = 0x01;
        system_data.mem_map[2] = 0x02;
        //bc
        let opcode = 0x01;
        load_nn_to_16bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.b_register, 2);
        assert_eq!(registers.c_register, 1);
        //de
        registers.program_counter -= 3;
        let opcode = 0x11;
        load_nn_to_16bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.d_register, 2);
        assert_eq!(registers.e_register, 1);
        //hl
        registers.program_counter -= 3;
        let opcode = 0x21;
        load_nn_to_16bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.h_register, 2);
        assert_eq!(registers.l_register, 1);
        //stack pointer
        registers.program_counter -= 3;
        let opcode = 0x31;
        load_nn_to_16bit_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.stack_pointer, 0x0201);

    }

    #[test]
    fn xor_register_test()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        let opcode = 0xAF;
        //A
        registers.accumulator = 0xFF;
        xor_register(&mut system_data, &mut registers, opcode);
        assert_eq!(registers.accumulator, 0);
    }

    #[test]
    fn pc_jumps_displacement_on_nonzero_flag()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        registers.program_counter = 100;
        //Positive Jump
        system_data.mem_map[101] = 10;
        registers.flags = 0x00;
        jump_displacement_on_nonzero_flag(&mut system_data, &mut registers);
        assert_eq!(registers.program_counter, 112);
        //Negative Jump
        registers.program_counter = 100;
        system_data.mem_map[101] = 253;
        registers.flags = 0x00;
        jump_displacement_on_nonzero_flag(&mut system_data, &mut registers);
        assert_eq!(registers.program_counter, 99);
        //Zero Flag
        registers.program_counter = 100;
        system_data.mem_map[101] = 0xFF;
        registers.flags = 0xFF;
        jump_displacement_on_nonzero_flag(&mut system_data, &mut registers);
        assert_eq!(registers.program_counter, 102)
    }

    #[test]
    fn load_decrement_hl_register_location_with_accumulator_test()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        //Normal increment
        registers.h_register = 0xFF;
        registers.l_register = 0xFF;
        registers.accumulator = 1;
        load_decrement_hl_register_location_with_accumulator(&mut system_data, &mut registers);
        assert_eq!(system_data.mem_map[0xFFFF], 1);
        assert_eq!(registers.h_register, 0xFF);
        assert_eq!(registers.l_register, 0xFE);
    }

    #[test]
    fn bit_check_register_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        //H
        //Zero Flag
        let opcode = 0x7C;
        let test_bit = 7;
        registers.h_register = 0x00;
        bit_check_register(&mut system_data, &mut registers, opcode, test_bit);
        assert_eq!(registers.flags, 0xA0);
        //No Zero Flag
        let opcode = 0x7C;
        let test_bit = 7;
        registers.h_register = 0xFF;
        bit_check_register(&mut system_data, &mut registers, opcode, test_bit);
        assert_eq!(registers.flags, 0x20);
    }

    #[test]
    fn load_hl_address_with_register_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        registers.h_register = 0xFF;
        registers.l_register = 0xFF;
        registers.accumulator = 1;
        registers.b_register = 2;
        registers.c_register = 3;
        registers.d_register = 4;
        registers.e_register = 5;

        //A
        let opcode = 0x77;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 1);
        //B
        let opcode = 0x70;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 2);
        //C
        let opcode = 0x71;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 3);
        //D
        let opcode = 0x72;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 4);
        //E
        let opcode = 0x73;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 5);
        //H
        let opcode = 0x74;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 0xFF);
        //L
        let opcode = 0x75;
        load_hl_address_with_register(&mut system_data, &mut registers, opcode);
        assert_eq!(system_data.mem_map[0xFFFF], 0xFF);
    }

    #[test]
    fn load_accumulator_to_io_port_with_a_offset_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        registers.accumulator = 1;
        system_data.mem_map[1] = 1;
        load_accumulator_to_io_port_with_n_offset(&mut system_data, &mut registers);
        assert_eq!(system_data.mem_map[0xFF01], 1);
    }

    #[test]
    fn load_8_bit_register_to_register_test()
    {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        let asserts = File::open("src/cpu/ld_r_r_asserts.csv").unwrap();
        let mut rdr_asserts = csv::ReaderBuilder::new().has_headers(false).from_reader(asserts);
        let opcodes = File::open("src/cpu/ld_r_r_opcodes.csv").unwrap();
        let mut rdr_opcodes = csv::ReaderBuilder::new().has_headers(false).from_reader(opcodes);
        let mut asserts: Vec<String> = Vec::new();
        let mut opcodes: Vec<String> = Vec::new();
        for record in rdr_asserts.records()
        {
            asserts.push(String::from(&(record.unwrap())[0]));
        }
        for record in rdr_opcodes.records()
        {
            opcodes.push(String::from(&(record.unwrap())[0]));
        }

        let mut count : u8 = 0;
        for index in 0..asserts.len()
        {
            if(index % 7 == 0){
                for i in 0..7
                {
                    registers.mapped_register_setter(i, i + 1)
                }
                if index > 0
                {
                    count += 1;
                }
            }
            let opcode = Vec::from_hex(&opcodes[index]).unwrap();
            load_8_bit_register_to_register(&mut system_data, &mut registers, opcode[0]);
            assert_eq!(asserts[index].parse::<u8>().unwrap(), registers.mapped_register_getter(count));
        }
    }

    #[test]
    fn load_accumulator_with_de_address_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut registers : Registers = init_registers();
        registers.d_register = 0xFF;
        registers.e_register = 0xEE;
        system_data.mem_map[0xFFEE] = 1;
        load_accumulator_with_de_address(&mut system_data, &mut registers);
        assert_eq!(registers.accumulator, 1);
    }

    // #[test]
    // fn call_nn_test() {
    //     unimplemented!();
    // }
}<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::result::Result as RResult;
use std::ops::Deref;

use toml::Value;

use error::RuntimeErrorKind as REK;
use libimagerror::into::IntoError;

generate_error_module!(
    generate_error_types!(ConfigError, ConfigErrorKind,
        TOMLParserError => "TOML Parsing error",
        NoConfigFileFound   => "No config file found",

        ConfigOverrideError => "Config override error",
        ConfigOverrideKeyNotAvailable => "Key not available",
        ConfigOverrideTypeNotMatching => "Configuration Type not matching"

    );
);

pub use self::error::{ConfigError, ConfigErrorKind};

/// Result type of this module. Either `T` or `ConfigError`
pub type Result<T> = RResult<T, ConfigError>;

/// `Configuration` object
///
/// Holds all config variables which are globally available plus the configuration object from the
/// config parser, which can be accessed.
#[derive(Debug)]
pub struct Configuration {

    /// The plain configuration object for direct access if necessary
    config: Value,

    /// The verbosity the program should run with
    verbosity: bool,

    /// The editor which should be used
    editor: Option<String>,

    ///The options the editor should get when opening some file
    editor_opts: String,
}

impl Configuration {

    /// Get a new configuration object.
    ///
    /// The passed runtimepath is used for searching the configuration file, whereas several file
    /// names are tested. If that does not work, the home directory and the XDG basedir are tested
    /// with all variants.
    ///
    /// If that doesn't work either, an error is returned.
    pub fn new(rtp: &PathBuf) -> Result<Configuration> {
        fetch_config(&rtp).map(|cfg| {
            let verbosity   = get_verbosity(&cfg);
            let editor      = get_editor(&cfg);
            let editor_opts = get_editor_opts(&cfg);

            debug!("Building configuration");
            debug!("  - verbosity  : {:?}", verbosity);
            debug!("  - editor     : {:?}", editor);
            debug!("  - editor-opts: {}", editor_opts);

            Configuration {
                config: cfg,
                verbosity: verbosity,
                editor: editor,
                editor_opts: editor_opts,
            }
        })
    }

    /// Get the Editor setting from the configuration
    pub fn editor(&self) -> Option<&String> {
        self.editor.as_ref()
    }

    /// Get the underlying configuration TOML object
    pub fn config(&self) -> &Value {
        &self.config
    }

    /// Get the configuration of the store, if any.
    pub fn store_config(&self) -> Option<&Value> {
        match self.config {
            Value::Table(ref tabl) => tabl.get("store"),
            _ => None,
        }
    }

    /// Override the configuration.
    /// The `v` parameter is expected to contain 'key=value' pairs where the key is a path in the
    /// TOML tree, the value to be an appropriate value.
    ///
    /// The override fails if the configuration which is about to be overridden does not exist or
    /// the `value` part cannot be converted to the type of the configuration value.
    ///
    /// If `v` is empty, this is considered to be a successful `override_config()` call.
    pub fn override_config(&mut self, v: Vec<String>) -> Result<()> {
        use libimagutil::key_value_split::*;
        use libimagutil::iter::*;
        use self::error::ConfigErrorKind as CEK;
        use self::error::MapErrInto;
        use libimagerror::into::IntoError;
        use libimagstore::toml_ext::TomlValueExt;

        v.into_iter()
            .map(|s| { debug!("Trying to process '{}'", s); s })
            .filter_map(|s| match s.into_kv() {
                Some(kv) => Some(kv.into()),
                None => {
                    warn!("Could split at '=' - will be ignore override");
                    None
                }
            })
            .map(|(k, v)| self
                 .config
                 .read(&k[..])
                 .map_err_into(CEK::TOMLParserError)
                 .map(|toml| match toml {
                    Some(value) => match into_value(value, v) {
                        Some(v) => {
                            info!("Successfully overridden: {} = {}", k, v);
                            Ok(v)
                        },
                        None => Err(CEK::ConfigOverrideTypeNotMatching.into_error()),
                    },
                    None => Err(CEK::ConfigOverrideKeyNotAvailable.into_error()),
                })
            )
            .fold_result(|i| i)
            .map_err(Box::new)
            .map_err(|e| CEK::ConfigOverrideError.into_error_with_cause(e))
    }
}

/// Tries to convert the String `s` into the same type as `value`.
///
/// Returns None if string cannot be converted.
///
/// Arrays and Tables are not supported and will yield `None`.
fn into_value(value: Value, s: String) -> Option<Value> {
    use std::str::FromStr;

    match value {
        Value::String(_)  => Some(Value::String(s)),
        Value::Integer(_) => FromStr::from_str(&s[..]).ok().map(Value::Integer),
        Value::Float(_)   => FromStr::from_str(&s[..]).ok().map(Value::Float),
        Value::Boolean(_) => {
            if s == "true" { Some(Value::Boolean(true)) }
            else if s == "false" { Some(Value::Boolean(false)) }
            else { None }
        }
        Value::Datetime(_) => Value::try_from(s).ok(),
        _ => None,
    }
}

impl Deref for Configuration {
    type Target = Value;

    fn deref(&self) -> &Value {
        &self.config
    }

}

fn get_verbosity(v: &Value) -> bool {
    match *v {
        Value::Table(ref t) => t.get("verbose")
                .map_or(false, |v| is_match!(v, &Value::Boolean(true))),
        _ => false,
    }
}

fn get_editor(v: &Value) -> Option<String> {
    match *v {
        Value::Table(ref t) => t.get("editor")
                .and_then(|v| match *v { Value::String(ref s) => Some(s.clone()), _ => None, }),
        _ => None,
    }
}

fn get_editor_opts(v: &Value) -> String {
    match *v {
        Value::Table(ref t) => t.get("editor-opts")
                .and_then(|v| match *v { Value::String(ref s) => Some(s.clone()), _ => None, })
                .unwrap_or_default(),
        _ => String::new(),
    }
}

/// Helper to fetch the config file
///
/// Tests several variants for the config file path and uses the first one which works.
fn fetch_config(rtp: &PathBuf) -> Result<Value> {
    use std::env;
    use std::fs::File;
    use std::io::Read;

    use xdg_basedir;
    use itertools::Itertools;

    use libimagutil::variants::generate_variants as gen_vars;
    use self::error::MapErrInto;

    let variants = vec!["config", "config.toml", "imagrc", "imagrc.toml"];
    let modifier = |base: &PathBuf, v: &'static str| {
        let mut base = base.clone();
        base.push(String::from(v));
        base
    };

    vec![
        vec![rtp.clone()],
        gen_vars(rtp.clone(), variants.clone(), &modifier),

        env::var("HOME").map(|home| gen_vars(PathBuf::from(home), variants.clone(), &modifier))
                        .unwrap_or(vec![]),

        xdg_basedir::get_data_home().map(|data_dir| gen_vars(data_dir, variants.clone(), &modifier))
                                    .unwrap_or(vec![]),
    ].iter()
        .flatten()
        .filter(|path| path.exists() && path.is_file())
        .map(|path| {
            debug!("Reading {:?}", path);
            let content = {
                let mut s = String::new();
                let f = File::open(path);
                if f.is_err() {
                    return None
                }
                let mut f = f.unwrap();
                f.read_to_string(&mut s).ok();
                s
            };

            trace!("Contents of config file: \n---\n{}\n---", content);

            let toml = ::toml::de::from_str(&content[..])
                .map_err_into(ConfigErrorKind::TOMLParserError)
                .map_err(Box::new)
                .map_err(|e| REK::Instantiate.into_error_with_cause(e));

            Some(toml)
        })
        .filter_map(|x| x)
        .filter(|loaded| loaded.is_ok())
        .map(|inner| Value::Table(inner.unwrap()))
        .nth(0)
        .ok_or(ConfigErrorKind::NoConfigFileFound.into())
}
<commit_msg>Minify map/filter_map<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::result::Result as RResult;
use std::ops::Deref;

use toml::Value;

use error::RuntimeErrorKind as REK;
use libimagerror::into::IntoError;

generate_error_module!(
    generate_error_types!(ConfigError, ConfigErrorKind,
        TOMLParserError => "TOML Parsing error",
        NoConfigFileFound   => "No config file found",

        ConfigOverrideError => "Config override error",
        ConfigOverrideKeyNotAvailable => "Key not available",
        ConfigOverrideTypeNotMatching => "Configuration Type not matching"

    );
);

pub use self::error::{ConfigError, ConfigErrorKind};

/// Result type of this module. Either `T` or `ConfigError`
pub type Result<T> = RResult<T, ConfigError>;

/// `Configuration` object
///
/// Holds all config variables which are globally available plus the configuration object from the
/// config parser, which can be accessed.
#[derive(Debug)]
pub struct Configuration {

    /// The plain configuration object for direct access if necessary
    config: Value,

    /// The verbosity the program should run with
    verbosity: bool,

    /// The editor which should be used
    editor: Option<String>,

    ///The options the editor should get when opening some file
    editor_opts: String,
}

impl Configuration {

    /// Get a new configuration object.
    ///
    /// The passed runtimepath is used for searching the configuration file, whereas several file
    /// names are tested. If that does not work, the home directory and the XDG basedir are tested
    /// with all variants.
    ///
    /// If that doesn't work either, an error is returned.
    pub fn new(rtp: &PathBuf) -> Result<Configuration> {
        fetch_config(&rtp).map(|cfg| {
            let verbosity   = get_verbosity(&cfg);
            let editor      = get_editor(&cfg);
            let editor_opts = get_editor_opts(&cfg);

            debug!("Building configuration");
            debug!("  - verbosity  : {:?}", verbosity);
            debug!("  - editor     : {:?}", editor);
            debug!("  - editor-opts: {}", editor_opts);

            Configuration {
                config: cfg,
                verbosity: verbosity,
                editor: editor,
                editor_opts: editor_opts,
            }
        })
    }

    /// Get the Editor setting from the configuration
    pub fn editor(&self) -> Option<&String> {
        self.editor.as_ref()
    }

    /// Get the underlying configuration TOML object
    pub fn config(&self) -> &Value {
        &self.config
    }

    /// Get the configuration of the store, if any.
    pub fn store_config(&self) -> Option<&Value> {
        match self.config {
            Value::Table(ref tabl) => tabl.get("store"),
            _ => None,
        }
    }

    /// Override the configuration.
    /// The `v` parameter is expected to contain 'key=value' pairs where the key is a path in the
    /// TOML tree, the value to be an appropriate value.
    ///
    /// The override fails if the configuration which is about to be overridden does not exist or
    /// the `value` part cannot be converted to the type of the configuration value.
    ///
    /// If `v` is empty, this is considered to be a successful `override_config()` call.
    pub fn override_config(&mut self, v: Vec<String>) -> Result<()> {
        use libimagutil::key_value_split::*;
        use libimagutil::iter::*;
        use self::error::ConfigErrorKind as CEK;
        use self::error::MapErrInto;
        use libimagerror::into::IntoError;
        use libimagstore::toml_ext::TomlValueExt;

        v.into_iter()
            .map(|s| { debug!("Trying to process '{}'", s); s })
            .filter_map(|s| match s.into_kv() {
                Some(kv) => Some(kv.into()),
                None => {
                    warn!("Could split at '=' - will be ignore override");
                    None
                }
            })
            .map(|(k, v)| self
                 .config
                 .read(&k[..])
                 .map_err_into(CEK::TOMLParserError)
                 .map(|toml| match toml {
                    Some(value) => match into_value(value, v) {
                        Some(v) => {
                            info!("Successfully overridden: {} = {}", k, v);
                            Ok(v)
                        },
                        None => Err(CEK::ConfigOverrideTypeNotMatching.into_error()),
                    },
                    None => Err(CEK::ConfigOverrideKeyNotAvailable.into_error()),
                })
            )
            .fold_result(|i| i)
            .map_err(Box::new)
            .map_err(|e| CEK::ConfigOverrideError.into_error_with_cause(e))
    }
}

/// Tries to convert the String `s` into the same type as `value`.
///
/// Returns None if string cannot be converted.
///
/// Arrays and Tables are not supported and will yield `None`.
fn into_value(value: Value, s: String) -> Option<Value> {
    use std::str::FromStr;

    match value {
        Value::String(_)  => Some(Value::String(s)),
        Value::Integer(_) => FromStr::from_str(&s[..]).ok().map(Value::Integer),
        Value::Float(_)   => FromStr::from_str(&s[..]).ok().map(Value::Float),
        Value::Boolean(_) => {
            if s == "true" { Some(Value::Boolean(true)) }
            else if s == "false" { Some(Value::Boolean(false)) }
            else { None }
        }
        Value::Datetime(_) => Value::try_from(s).ok(),
        _ => None,
    }
}

impl Deref for Configuration {
    type Target = Value;

    fn deref(&self) -> &Value {
        &self.config
    }

}

fn get_verbosity(v: &Value) -> bool {
    match *v {
        Value::Table(ref t) => t.get("verbose")
                .map_or(false, |v| is_match!(v, &Value::Boolean(true))),
        _ => false,
    }
}

fn get_editor(v: &Value) -> Option<String> {
    match *v {
        Value::Table(ref t) => t.get("editor")
                .and_then(|v| match *v { Value::String(ref s) => Some(s.clone()), _ => None, }),
        _ => None,
    }
}

fn get_editor_opts(v: &Value) -> String {
    match *v {
        Value::Table(ref t) => t.get("editor-opts")
                .and_then(|v| match *v { Value::String(ref s) => Some(s.clone()), _ => None, })
                .unwrap_or_default(),
        _ => String::new(),
    }
}

/// Helper to fetch the config file
///
/// Tests several variants for the config file path and uses the first one which works.
fn fetch_config(rtp: &PathBuf) -> Result<Value> {
    use std::env;
    use std::fs::File;
    use std::io::Read;

    use xdg_basedir;
    use itertools::Itertools;

    use libimagutil::variants::generate_variants as gen_vars;
    use self::error::MapErrInto;

    let variants = vec!["config", "config.toml", "imagrc", "imagrc.toml"];
    let modifier = |base: &PathBuf, v: &'static str| {
        let mut base = base.clone();
        base.push(String::from(v));
        base
    };

    vec![
        vec![rtp.clone()],
        gen_vars(rtp.clone(), variants.clone(), &modifier),

        env::var("HOME").map(|home| gen_vars(PathBuf::from(home), variants.clone(), &modifier))
                        .unwrap_or(vec![]),

        xdg_basedir::get_data_home().map(|data_dir| gen_vars(data_dir, variants.clone(), &modifier))
                                    .unwrap_or(vec![]),
    ].iter()
        .flatten()
        .filter(|path| path.exists() && path.is_file())
        .filter_map(|path| if path.exists() && path.is_file() {
            debug!("Reading {:?}", path);
            let content = {
                let mut s = String::new();
                let f = File::open(path);
                if f.is_err() {
                    return None
                }
                let mut f = f.unwrap();
                f.read_to_string(&mut s).ok();
                s
            };

            trace!("Contents of config file: \n---\n{}\n---", content);

            let toml = ::toml::de::from_str(&content[..])
                .map_err_into(ConfigErrorKind::TOMLParserError)
                .map_err(Box::new)
                .map_err(|e| REK::Instantiate.into_error_with_cause(e));

            Some(toml)
        } else {
            None
        })
        .filter(|loaded| loaded.is_ok())
        .map(|inner| Value::Table(inner.unwrap()))
        .nth(0)
        .ok_or(ConfigErrorKind::NoConfigFileFound.into())
}
<|endoftext|>


<commit_before>#![allow(unsafe_code)]
#![allow(unused)]

use std::{
    alloc::{alloc_zeroed, dealloc, Layout},
    convert::{TryFrom, TryInto},
    fmt,
    mem::{align_of, size_of, ManuallyDrop},
    num::NonZeroU64,
    ops::{Deref, DerefMut, Index, IndexMut},
};

const ALIGNMENT: usize = align_of::<Header>();
const U64_SZ: usize = size_of::<u64>();

// allocates space for a header struct at the beginning.
fn aligned_boxed_slice(size: usize) -> Box<[u8]> {
    let size = size + size_of::<Header>();
    let layout = Layout::from_size_align(size, ALIGNMENT).unwrap();

    unsafe {
        let ptr = alloc_zeroed(layout);
        let fat_ptr = fatten(ptr, size);
        let ret = Box::from_raw(fat_ptr);
        assert_eq!(ret.len(), size);
        ret
    }
}

/// <https://users.rust-lang.org/t/construct-fat-pointer-to-struct/29198/9>
#[allow(trivial_casts)]
#[inline]
fn fatten(data: *const u8, len: usize) -> *mut [u8] {
    // Requirements of slice::from_raw_parts.
    assert!(!data.is_null());
    assert!(isize::try_from(len).is_ok());

    let slice = unsafe { core::slice::from_raw_parts(data as *const (), len) };
    slice as *const [()] as *mut _
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub(crate) struct Header {
    // NB always lay out fields from largest to smallest
    // to properly pack the struct
    pub next: Option<NonZeroU64>,
    pub merging_child: Option<NonZeroU64>,
    //fixed_key_length: Option<NonZeroU64>,
    pub children: u16,
    pub prefix_len: u8,
    pub merging: bool,
    pub is_index: bool,
}

pub(crate) struct InlineRecords(ManuallyDrop<Box<[u8]>>);

impl Drop for InlineRecords {
    fn drop(&mut self) {
        let box_ptr = self.0.as_mut_ptr();
        let layout = Layout::from_size_align(self.0.len(), ALIGNMENT).unwrap();
        unsafe {
            dealloc(box_ptr, layout);
        }
    }
}

impl Deref for InlineRecords {
    type Target = Header;

    fn deref(&self) -> &Header {
        self.header()
    }
}

impl fmt::Debug for InlineRecords {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("InlineRecords")
            .field("header", self.header())
            .field("lo", &self.lo())
            .field("hi", &self.hi())
            .field("items", &self.iter().collect::<crate::Map<_, _>>())
            .finish()
    }
}

impl DerefMut for InlineRecords {
    fn deref_mut(&mut self) -> &mut Header {
        self.header_mut()
    }
}

impl InlineRecords {
    fn new(
        hi: &[u8],
        lo: &[u8],
        prefix_len: u8,
        items: &[(&[u8], u64)],
    ) -> InlineRecords {
        let offsets_and_lengths_size =
            (2 * size_of::<u64>()) * (2 + items.len());
        let keys_and_values_size =
            items.iter().map(|(k, _pid)| k.len()).sum::<usize>()
                + size_of::<u64>() * (2 + items.len());

        let boxed_slice = aligned_boxed_slice(
            offsets_and_lengths_size + keys_and_values_size,
        );

        let mut ret = InlineRecords(ManuallyDrop::new(boxed_slice));
        ret.next = None;
        ret.merging_child = None;
        ret.children = u16::try_from(items.len()).unwrap();
        ret.prefix_len = prefix_len;
        ret.merging = false;
        ret.is_index = true;

        let data_buf = &mut ret.0[size_of::<Header>()..];
        let (offsets, lengths_keys_and_values) =
            data_buf.split_at_mut(offsets_and_lengths_size);

        let bounds = [(lo, 0), (hi, 0)];
        let iter = bounds.iter().chain(items.into_iter());

        let mut kv_cursor = 0_usize;
        for (idx, (key, pid)) in iter.enumerate() {
            let offsets_cursor = idx * U64_SZ;
            offsets[offsets_cursor..offsets_cursor + U64_SZ]
                .copy_from_slice(&kv_cursor.to_le_bytes());

            lengths_keys_and_values[kv_cursor..kv_cursor + U64_SZ]
                .copy_from_slice(&(key.len() as u64).to_le_bytes());
            kv_cursor += U64_SZ;

            lengths_keys_and_values[kv_cursor..kv_cursor + key.len()]
                .copy_from_slice(key);
            kv_cursor += key.len();

            lengths_keys_and_values[kv_cursor..kv_cursor + U64_SZ]
                .copy_from_slice(&pid.to_le_bytes());
            kv_cursor += U64_SZ;
        }

        ret
    }

    fn header(&self) -> &Header {
        unsafe { &*(self.0.as_ptr() as *mut Header) }
    }

    fn header_mut(&mut self) -> &mut Header {
        unsafe { &mut *(self.0.as_mut_ptr() as *mut Header) }
    }

    fn len(&self) -> usize {
        usize::from(self.children)
    }

    fn find(&self, key: &[u8]) -> Result<usize, usize> {
        todo!()
    }

    fn insert(&mut self, key: &[u8], pid: u64) {
        match self.find(&key[usize::from(self.prefix_len)..]) {
            Ok(offset) => {
                if self.is_index {
                    panic!("already contained key being merged into index");
                }
                todo!()
            }
            Err(prospective_offset) => {
                todo!()
            }
        }
    }

    fn get_lub(&self, key: &[u8]) -> u64 {
        assert!(key >= self.lo());
        todo!()
    }

    fn iter(&self) -> impl Iterator<Item = (&[u8], u64)> {
        (0..usize::from(self.children)).map(move |idx| self.index(idx))
    }

    fn lo(&self) -> &[u8] {
        self.index(0).0
    }

    fn hi(&self) -> &[u8] {
        self.index(1).0
    }

    fn index(&self, idx: usize) -> (&[u8], u64) {
        assert!(idx < usize::from(self.children));

        let raw = self.index_raw(idx);

        let pivot = raw.len() - U64_SZ;

        let (key, pid_bytes) = raw.split_at(pivot);

        (key, u64::from_le_bytes(pid_bytes.try_into().unwrap()))
    }

    fn index_raw(&self, idx: usize) -> &[u8] {
        assert!(idx <= usize::from(self.children));
        let offsets_start = size_of::<Header>();
        let offsets_end = offsets_start + (usize::from(self.children) * U64_SZ);
        let offsets = &self.0[offsets_start..offsets_end];
        let offset = &offsets[U64_SZ * idx..U64_SZ * (idx + 1)];

        let offset_slice = &offset[..U64_SZ];

        let offset =
            u64::from_le_bytes(offset_slice.try_into().unwrap()) as usize;

        let length_key_and_value = &self.0[offsets_end + offset..];

        let length_buf = &length_key_and_value[..U64_SZ];
        let length =
            u64::from_le_bytes(length_buf.try_into().unwrap()) as usize;

        let length =
            u64::from_le_bytes(offset_slice.try_into().unwrap()) as usize;

        let start = offset + U64_SZ;
        let end = start + length + U64_SZ;

        &length_key_and_value[start..end]
    }
}

fn varint_size(int: u64) -> u64 {
    if int <= 240 {
        1
    } else if int <= 2287 {
        2
    } else if int <= 67823 {
        3
    } else if int <= 0x00FF_FFFF {
        4
    } else if int <= 0xFFFF_FFFF {
        5
    } else if int <= 0x00FF_FFFF_FFFF {
        6
    } else if int <= 0xFFFF_FFFF_FFFF {
        7
    } else if int <= 0x00FF_FFFF_FFFF_FFFF {
        8
    } else {
        9
    }
}

fn serialize_varint_into(int: u64, buf: &mut [u8]) {
    if int <= 240 {
        buf[0] = u8::try_from(int).unwrap();
    } else if int <= 2287 {
        buf[0] = u8::try_from((int - 240) / 256 + 241).unwrap();
        buf[1] = u8::try_from((int - 240) % 256).unwrap();
    } else if int <= 67823 {
        buf[0] = 249;
        buf[1] = u8::try_from((int - 2288) / 256).unwrap();
        buf[2] = u8::try_from((int - 2288) % 256).unwrap();
    } else if int <= 0x00FF_FFFF {
        buf[0] = 250;
        let bytes = int.to_le_bytes();
        buf[1..4].copy_from_slice(&bytes[..3]);
    } else if int <= 0xFFFF_FFFF {
        buf[0] = 251;
        let bytes = int.to_le_bytes();
        buf[1..5].copy_from_slice(&bytes[..4]);
    } else if int <= 0x00FF_FFFF_FFFF {
        buf[0] = 252;
        let bytes = int.to_le_bytes();
        buf[1..6].copy_from_slice(&bytes[..5]);
    } else if int <= 0xFFFF_FFFF_FFFF {
        buf[0] = 253;
        let bytes = int.to_le_bytes();
        buf[1..7].copy_from_slice(&bytes[..6]);
    } else if int <= 0x00FF_FFFF_FFFF_FFFF {
        buf[0] = 254;
        let bytes = int.to_le_bytes();
        buf[1..8].copy_from_slice(&bytes[..7]);
    } else {
        buf[0] = 255;
        let bytes = int.to_le_bytes();
        buf[1..9].copy_from_slice(&bytes[..8]);
    };
}

fn deserialize_varint(buf: &[u8]) -> crate::Result<u64> {
    if buf.is_empty() {
        return Err(crate::Error::corruption(None));
    }
    let res = match buf[0] {
        0..=240 => u64::from(buf[0]),
        241..=248 => 240 + 256 * (u64::from(buf[0]) - 241) + u64::from(buf[1]),
        249 => 2288 + 256 * u64::from(buf[1]) + u64::from(buf[2]),
        other => {
            let sz = other as usize - 247;
            let mut aligned = [0; 8];
            aligned[..sz].copy_from_slice(&buf[1..=sz]);
            u64::from_le_bytes(aligned)
        }
    };
    Ok(res)
}

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

    #[test]
    fn simple() {
        let mut ir = InlineRecords::new(&[], &[], 0, &[]);
        let header: &mut Header = ir.header_mut();
        header.next = Some(NonZeroU64::new(5).unwrap());
        header.is_index = true;
        dbg!(header);
        println!("ir: {:?}", ir);
    }
}
<commit_msg>Fix some alignment issues<commit_after>#![allow(unsafe_code)]
#![allow(unused)]

use std::{
    alloc::{alloc_zeroed, dealloc, Layout},
    convert::{TryFrom, TryInto},
    fmt,
    mem::{align_of, size_of, ManuallyDrop},
    num::NonZeroU64,
    ops::{Deref, DerefMut, Index, IndexMut},
};

const ALIGNMENT: usize = align_of::<Header>();
const U64_SZ: usize = size_of::<u64>();

// allocates space for a header struct at the beginning.
fn aligned_boxed_slice(size: usize) -> Box<[u8]> {
    let size = size + size_of::<Header>();
    let layout = Layout::from_size_align(size, ALIGNMENT).unwrap();

    unsafe {
        let ptr = alloc_zeroed(layout);
        let fat_ptr = fatten(ptr, size);
        let ret = Box::from_raw(fat_ptr);
        assert_eq!(ret.len(), size);
        ret
    }
}

/// <https://users.rust-lang.org/t/construct-fat-pointer-to-struct/29198/9>
#[allow(trivial_casts)]
#[inline]
fn fatten(data: *const u8, len: usize) -> *mut [u8] {
    // Requirements of slice::from_raw_parts.
    assert!(!data.is_null());
    assert!(isize::try_from(len).is_ok());

    let slice = unsafe { core::slice::from_raw_parts(data as *const (), len) };
    slice as *const [()] as *mut _
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub(crate) struct Header {
    // NB always lay out fields from largest to smallest
    // to properly pack the struct
    pub next: Option<NonZeroU64>,
    pub merging_child: Option<NonZeroU64>,
    //fixed_key_length: Option<NonZeroU64>,
    pub children: u16,
    pub prefix_len: u8,
    pub merging: bool,
    pub is_index: bool,
}

pub(crate) struct InlineRecords(ManuallyDrop<Box<[u8]>>);

impl Drop for InlineRecords {
    fn drop(&mut self) {
        let box_ptr = self.0.as_mut_ptr();
        let layout = Layout::from_size_align(self.0.len(), ALIGNMENT).unwrap();
        unsafe {
            dealloc(box_ptr, layout);
        }
    }
}

impl Deref for InlineRecords {
    type Target = Header;

    fn deref(&self) -> &Header {
        self.header()
    }
}

impl fmt::Debug for InlineRecords {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("InlineRecords")
            .field("header", self.header())
            .field("lo", &self.lo())
            .field("hi", &self.hi())
            .field("items", &self.iter().collect::<crate::Map<_, _>>())
            .finish()
    }
}

impl DerefMut for InlineRecords {
    fn deref_mut(&mut self) -> &mut Header {
        self.header_mut()
    }
}

impl InlineRecords {
    fn new(
        hi: &[u8],
        lo: &[u8],
        prefix_len: u8,
        items: &[(&[u8], u64)],
    ) -> InlineRecords {
        let offsets_size = size_of::<u64>() * (2 + items.len());
        let keys_and_values_size =
            items.iter().map(|(k, _pid)| k.len()).sum::<usize>()
                + (2 * size_of::<u64>()) * (2 + items.len());

        println!("allocating size of {}", offsets_size + keys_and_values_size);
        let boxed_slice =
            aligned_boxed_slice(offsets_size + keys_and_values_size);

        let mut ret = InlineRecords(ManuallyDrop::new(boxed_slice));
        ret.next = None;
        ret.merging_child = None;
        ret.children = u16::try_from(items.len()).unwrap();
        ret.prefix_len = prefix_len;
        ret.merging = false;
        ret.is_index = true;

        let data_buf = &mut ret.0[size_of::<Header>()..];
        let (offsets, lengths_keys_and_values) =
            data_buf.split_at_mut(offsets_size);

        let bounds = [(lo, 0), (hi, 0)];
        let iter = bounds.iter().chain(items.into_iter());

        let mut kv_cursor = 0_usize;
        for (idx, (key, pid)) in iter.enumerate() {
            let offsets_cursor = idx * U64_SZ;
            offsets[offsets_cursor..offsets_cursor + U64_SZ]
                .copy_from_slice(&kv_cursor.to_le_bytes());

            lengths_keys_and_values[kv_cursor..kv_cursor + U64_SZ]
                .copy_from_slice(&(key.len() as u64).to_le_bytes());
            kv_cursor += U64_SZ;

            lengths_keys_and_values[kv_cursor..kv_cursor + key.len()]
                .copy_from_slice(key);
            kv_cursor += key.len();

            lengths_keys_and_values[kv_cursor..kv_cursor + U64_SZ]
                .copy_from_slice(&pid.to_le_bytes());
            kv_cursor += U64_SZ;
            dbg!(kv_cursor);
        }

        ret
    }

    fn header(&self) -> &Header {
        unsafe { &*(self.0.as_ptr() as *mut Header) }
    }

    fn header_mut(&mut self) -> &mut Header {
        unsafe { &mut *(self.0.as_mut_ptr() as *mut Header) }
    }

    pub(crate) fn len(&self) -> usize {
        usize::from(self.children)
    }

    fn len_internal(&self) -> usize {
        self.len() + 2
    }

    fn find(&self, key: &[u8]) -> Result<usize, usize> {
        todo!()
    }

    fn insert(&mut self, key: &[u8], pid: u64) {
        match self.find(&key[usize::from(self.prefix_len)..]) {
            Ok(offset) => {
                if self.is_index {
                    panic!("already contained key being merged into index");
                }
                todo!()
            }
            Err(prospective_offset) => {
                todo!()
            }
        }
    }

    fn get_lub(&self, key: &[u8]) -> u64 {
        assert!(key >= self.lo());
        todo!()
    }

    fn iter(&self) -> impl Iterator<Item = (&[u8], u64)> {
        (2..)
            .take_while(move |idx| *idx < self.len_internal())
            .map(move |idx| self.index(idx))
    }

    fn lo(&self) -> &[u8] {
        self.index(0).0
    }

    fn hi(&self) -> &[u8] {
        self.index(1).0
    }

    fn index(&self, idx: usize) -> (&[u8], u64) {
        assert!(
            idx < self.len_internal(),
            "index {} is not less than internal length of {}",
            idx,
            self.len_internal()
        );

        let raw = self.index_raw_kv(idx);

        let pivot = raw.len() - U64_SZ;

        let (key, pid_bytes) = raw.split_at(pivot);

        (key, u64::from_le_bytes(pid_bytes.try_into().unwrap()))
    }

    fn index_raw_kv(&self, idx: usize) -> &[u8] {
        assert!(idx <= self.len_internal());
        let data_buf = &self.0[size_of::<Header>()..];
        let offsets_len = self.len_internal() * U64_SZ;
        let (offsets, items) = data_buf.split_at(offsets_len);

        let offset_buf = &offsets[U64_SZ * idx..U64_SZ * (idx + 1)];
        let kv_offset =
            u64::from_le_bytes(offset_buf.try_into().unwrap()) as usize;

        let item_buf = &items[kv_offset..];
        let len_buf = &item_buf[..U64_SZ];
        let key_len = u64::from_le_bytes(len_buf.try_into().unwrap()) as usize;
        let val_len = U64_SZ;

        let start = U64_SZ;
        let end = (2 * U64_SZ) + key_len;

        &item_buf[start..end]
    }
}

fn varint_size(int: u64) -> u64 {
    if int <= 240 {
        1
    } else if int <= 2287 {
        2
    } else if int <= 67823 {
        3
    } else if int <= 0x00FF_FFFF {
        4
    } else if int <= 0xFFFF_FFFF {
        5
    } else if int <= 0x00FF_FFFF_FFFF {
        6
    } else if int <= 0xFFFF_FFFF_FFFF {
        7
    } else if int <= 0x00FF_FFFF_FFFF_FFFF {
        8
    } else {
        9
    }
}

fn serialize_varint_into(int: u64, buf: &mut [u8]) {
    if int <= 240 {
        buf[0] = u8::try_from(int).unwrap();
    } else if int <= 2287 {
        buf[0] = u8::try_from((int - 240) / 256 + 241).unwrap();
        buf[1] = u8::try_from((int - 240) % 256).unwrap();
    } else if int <= 67823 {
        buf[0] = 249;
        buf[1] = u8::try_from((int - 2288) / 256).unwrap();
        buf[2] = u8::try_from((int - 2288) % 256).unwrap();
    } else if int <= 0x00FF_FFFF {
        buf[0] = 250;
        let bytes = int.to_le_bytes();
        buf[1..4].copy_from_slice(&bytes[..3]);
    } else if int <= 0xFFFF_FFFF {
        buf[0] = 251;
        let bytes = int.to_le_bytes();
        buf[1..5].copy_from_slice(&bytes[..4]);
    } else if int <= 0x00FF_FFFF_FFFF {
        buf[0] = 252;
        let bytes = int.to_le_bytes();
        buf[1..6].copy_from_slice(&bytes[..5]);
    } else if int <= 0xFFFF_FFFF_FFFF {
        buf[0] = 253;
        let bytes = int.to_le_bytes();
        buf[1..7].copy_from_slice(&bytes[..6]);
    } else if int <= 0x00FF_FFFF_FFFF_FFFF {
        buf[0] = 254;
        let bytes = int.to_le_bytes();
        buf[1..8].copy_from_slice(&bytes[..7]);
    } else {
        buf[0] = 255;
        let bytes = int.to_le_bytes();
        buf[1..9].copy_from_slice(&bytes[..8]);
    };
}

fn deserialize_varint(buf: &[u8]) -> crate::Result<u64> {
    if buf.is_empty() {
        return Err(crate::Error::corruption(None));
    }
    let res = match buf[0] {
        0..=240 => u64::from(buf[0]),
        241..=248 => 240 + 256 * (u64::from(buf[0]) - 241) + u64::from(buf[1]),
        249 => 2288 + 256 * u64::from(buf[1]) + u64::from(buf[2]),
        other => {
            let sz = other as usize - 247;
            let mut aligned = [0; 8];
            aligned[..sz].copy_from_slice(&buf[1..=sz]);
            u64::from_le_bytes(aligned)
        }
    };
    Ok(res)
}

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

    #[test]
    fn simple() {
        let mut ir =
            InlineRecords::new(&[], &[7], 0, &[(&[42], 42), (&[6, 6, 6], 66)]);
        ir.next = Some(NonZeroU64::new(5).unwrap());
        ir.is_index = false;
        dbg!(ir.header());
        println!("ir: {:#?}", ir);
    }
}
<|endoftext|>