<commit_before>// Streambuffer -- Fast asynchronous file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Streambuffer, a library for fast asynchronous file reading.
//!
//! # Examples
//!
//! Map a file into memory and access it as an array of bytes. This is simple and will generally
//! outperform `Read::read_to_end()`, but it will block upon first access.
//!
//! ```
//! use streambuffer::StreamBuffer;
//! let fstream = StreamBuffer::open("src/lib.rs").unwrap();
//! let buffer = fstream.as_slice();
//! assert_eq!(buffer[3..49], b"Streambuffer -- Fast asynchronous file reading"[..]);
//! ```
//!
//! TODO: More and better (non-blocking) examples.

#![warn(missing_docs)]

use std::io;
use std::fs;
use std::os::unix::io::AsRawFd;
use std::path::Path;
use std::slice;

extern crate libc;

/// A memory-mapped file.
pub struct StreamBuffer {
  buffer: *const u8,
  length: usize,
}

fn map_file(file: &fs::File) -> io::Result<(*const u8, usize)> {
    let fd = file.as_raw_fd();
    let length = try!(file.metadata()).len();

    if length > usize::max_value() as u64 {
        return Err(io::Error::new(io::ErrorKind::Other, "file is larger than address space"));
    }

    if length == 0 {
        return Err(io::Error::new(io::ErrorKind::Other, "file has size zero"));
    }

    let null = 0 as *mut libc::c_void;
    let result = unsafe {
        libc::mmap(null, length as usize, libc::PROT_READ, libc::MAP_PRIVATE, fd, 0)
    };

    if result == libc::MAP_FAILED {
        Err(io::Error::last_os_error())
    } else {
        Ok((result as *const u8, length as usize))
    }
}

fn unmap_file(buffer: *const u8, length: usize) {
    let result = unsafe {
        libc::munmap(buffer as *mut libc::c_void, length)
    };

    // `munmap` only fails due to incorrect usage, which is a program error, not a runtime failure.
    assert!(result == 0);
}

impl StreamBuffer {
    /// Maps the file at `path` into memory.
    ///
    /// TODO: Document what happens when the file is changed after opening.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<StreamBuffer> {
        // Open the `fs::File` so we get all of std's error handling for free, then use it to
        // extract the file descriptor. The file is closed again when it goes out of scope, but
        // `mmap` only requires the descriptor to be open for the `mmap` call, so this is fine.
        let file = try!(fs::File::open(path));
        let (buffer, length) = try!(map_file(&file));
        let fstream = StreamBuffer {
            buffer: buffer,
            length: length,
        };
        Ok(fstream)
    }

    /// Returns the file contents as a slice.
    ///
    /// Accessing elements of the slice might cause a page fault,
    /// blocking until the data has been read from disk.
    pub fn as_slice(&self) -> &[u8] {
       unsafe { slice::from_raw_parts(self.buffer, self.length) }
    }
}

impl Drop for StreamBuffer {
    fn drop(&mut self) {
        unmap_file(self.buffer, self.length);
    }
}

#[test]
fn open_file() {
    let fstream = StreamBuffer::open("src/lib.rs");
    assert!(fstream.is_ok());
}
<commit_msg>Add len() and resident_len() methods<commit_after>// Streambuffer -- Fast asynchronous file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Streambuffer, a library for fast asynchronous file reading.
//!
//! # Examples
//!
//! Map a file into memory and access it as an array of bytes. This is simple and will generally
//! outperform `Read::read_to_end()`, but it will block upon first access.
//!
//! ```
//! use streambuffer::StreamBuffer;
//! let fstream = StreamBuffer::open("src/lib.rs").unwrap();
//! let buffer = fstream.as_slice();
//! assert_eq!(buffer[3..49], b"Streambuffer -- Fast asynchronous file reading"[..]);
//! ```
//!
//! TODO: More and better (non-blocking) examples.

#![warn(missing_docs)]

use std::cmp;
use std::io;
use std::fs;
use std::os::unix::io::AsRawFd;
use std::path::Path;
use std::slice;
use std::thread;

extern crate libc;

/// A memory-mapped file.
pub struct StreamBuffer {
  page_size: usize,
  buffer: *const u8,
  length: usize,
}

fn map_file(file: &fs::File) -> io::Result<(*const u8, usize)> {
    let fd = file.as_raw_fd();
    let length = try!(file.metadata()).len();

    if length > usize::max_value() as u64 {
        return Err(io::Error::new(io::ErrorKind::Other, "file is larger than address space"));
    }

    if length == 0 {
        return Err(io::Error::new(io::ErrorKind::Other, "file has size zero"));
    }

    let null = 0 as *mut libc::c_void;
    let result = unsafe {
        libc::mmap(null, length as usize, libc::PROT_READ, libc::MAP_PRIVATE, fd, 0)
    };

    if result == libc::MAP_FAILED {
        Err(io::Error::last_os_error())
    } else {
        Ok((result as *const u8, length as usize))
    }
}

fn unmap_file(buffer: *const u8, length: usize) {
    let result = unsafe {
        libc::munmap(buffer as *mut libc::c_void, length)
    };

    // `munmap` only fails due to incorrect usage, which is a program error, not a runtime failure.
    assert!(result == 0);
}

/// Writes whether the pages in the range starting at `buffer` with a length of `length` bytes
/// are resident in physical memory into `residency`. The size of `residency` must be at least
/// `length / page_size`. Both `buffer` and `length` must be a multiple of the page size.
fn get_resident(buffer: *const u8, length: usize, residency: &mut [bool]) {
    let result = unsafe {
        let residency_uchar = residency.as_mut_ptr() as *mut libc::c_uchar;
        libc::mincore(buffer as *mut libc::c_void, length, residency_uchar)
    };

    // Any error code except EAGAIN indicates a programming error.
    assert!(result == libc::EAGAIN || result == 0);

    // In the rare occasion that the kernel is busy, yield so we don't spam the kernel with
    // `mincore` calls, then try again.
    if result == libc::EAGAIN {
        thread::yield_now();
        get_resident(buffer, length, residency)
    }
}

fn get_page_size() -> usize {
    let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };

    // Assert that the page size is a power of two, which is assumed when the page size is used.
    assert!(page_size != 0);
    assert_eq!(0, page_size & (page_size - 1));

    page_size
}

/// Rounds `size` up to the nearest multiple of `power_of_two`.
fn round_up_to(size: usize, power_of_two: usize) -> usize {
    (size + (power_of_two - 1)) & !(power_of_two - 1)
}

#[test]
fn verify_round_up_to() {
    assert_eq!(1024, round_up_to(23, 1024));
    assert_eq!(1024, round_up_to(1024, 1024));
    assert_eq!(2048, round_up_to(1025, 1024));
}

/// Rounds `size` down to the nearest multiple of `power_of_two`.
fn round_down_to(size: usize, power_of_two: usize) -> usize {
    size & !(power_of_two - 1)
}

#[test]
fn verify_round_down_to() {
    assert_eq!(0, round_down_to(23, 1024));
    assert_eq!(1024, round_down_to(1024, 1024));
    assert_eq!(1024, round_down_to(1025, 1024));
}

impl StreamBuffer {
    /// Maps the file at `path` into memory.
    ///
    /// TODO: Document what happens when the file is changed after opening.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<StreamBuffer> {
        // Open the `fs::File` so we get all of std's error handling for free, then use it to
        // extract the file descriptor. The file is closed again when it goes out of scope, but
        // `mmap` only requires the descriptor to be open for the `mmap` call, so this is fine.
        let file = try!(fs::File::open(path));
        let (buffer, length) = try!(map_file(&file));
        let fstream = StreamBuffer {
            page_size: get_page_size(),
            buffer: buffer,
            length: length,
        };
        Ok(fstream)
    }

    /// Returns the file contents as a slice.
    ///
    /// Accessing elements of the slice might cause a page fault,
    /// blocking until the data has been read from disk.
    pub fn as_slice(&self) -> &[u8] {
       unsafe { slice::from_raw_parts(self.buffer, self.length) }
    }

    /// Returns the length of the mapped file in bytes.
    pub fn len(&self) -> usize {
        self.length
    }

    /// Returns the number of bytes resident in physical memory, starting from `offset`.
    ///
    /// The slice `[offset..offset + resident_len]` can be accessed without causing page faults or
    /// disk access. Note that this is only a snapshot, and the kernel might decide to evict pages
    /// or make them resident at any time.
    ///
    /// The returned resident length is at most `length`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn resident_len(&self, offset: usize, length: usize) -> usize {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);
        let num_pages = aligned_length / self.page_size;

        // There is a tradeoff here: to store residency information, we need an array of booleans.
        // The requested range can potentially be very large and it is only known at runtime. We
        // could allocate a vector here, but that requires a heap allocation just to get residency
        // information (which might in turn cause a page fault). Instead, check at most 32 pages at
        // once. This means more syscalls for large ranges, but it saves us the heap allocation,
        // and for ranges up to 32 pages (128 KiB typically) there is only one syscall.
        let mut residency = [false; 32];
        let mut pages_checked = 0;
        let mut pages_resident = 0;

        while pages_checked < num_pages {
            let pages_to_check = cmp::min(32, num_pages - pages_checked);
            let check_offset = (aligned_offset + pages_checked * self.page_size) as isize;
            let check_buffer = unsafe { self.buffer.offset(check_offset) };
            let check_length = pages_to_check * self.page_size;
            get_resident(check_buffer, check_length, &mut residency);

            // Count the number of resident pages.
            match residency[..pages_to_check].iter().position(|resident| !resident) {
                Some(non_resident) => {
                    // The index of the non-resident page is the number of resident pages.
                    pages_resident += non_resident;
                    break;
                }
                None => {
                    pages_resident += pages_to_check;
                    pages_checked += pages_to_check;
                }
            }
        }

        let resident_length = pages_resident * self.page_size + aligned_offset - offset;

        // Never return more than the requested length. The resident length might be larger than
        // the length of the buffer, because it is rounded up to the page size.
        cmp::min(length, resident_length)
    }
}

impl Drop for StreamBuffer {
    fn drop(&mut self) {
        unmap_file(self.buffer, self.length);
    }
}

#[test]
fn open_file() {
    let fstream = StreamBuffer::open("src/lib.rs");
    assert!(fstream.is_ok());
}

#[test]
fn make_resident() {
    let fstream = StreamBuffer::open("src/lib.rs").unwrap();

    // Touch the first page to make it resident.
    assert_eq!(fstream.as_slice()[3..15], b"Streambuffer"[..]);

    // Now at least that part should be resident.
    assert_eq!(fstream.resident_len(3, 12), 12);
}
<|endoftext|>


<commit_before>#![feature(core, collections)]
#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::borrow::Cow;
use std::string::CowString;

#[cfg(test)]
mod tests;

#[derive(Debug)]
pub struct IrcMessage<'a> {
    pub tags: HashMap<CowString<'a>, CowString<'a>>,
    pub prefix: Option<CowString<'a>>,
    pub command: Option<CowString<'a>>,
    pub params: Vec<CowString<'a>>
}

impl <'b> IrcMessage<'b> {
    pub fn new_empty<'a>() -> IrcMessage<'a> {
        IrcMessage {
            tags: HashMap::new(),
            prefix: None,
            command: None,
            params: Vec::new()
        }
    }

    /// Parse a message from a string to an owned `IrcMessage`.
    pub fn parse_owned<'a>(s: &'a str) -> Result<IrcMessage<'static>, ()> {
        return parse_owned(s);
    }

    /// Parse a message from a string to an `IrcMessage` that still refers
    /// to the original `str`.  Useful for minimizing allocations.
    pub fn parse_slice<'a>(s: &'a str) -> Result<IrcMessage<'a>, ()> {
        return parse_slice(s);
    }
}

fn next_segment<'a>(line: &'a str) -> (&'a str, &'a str) {
    match line.find(' ') {
        Some(n) => {
            if line.len() == 0 {
                return (line, line);
            }
            let segment = &line[..n];

            let mut p = n;

            while line.char_at(p) == ' ' && p < line.len() - 1 {
                p += 1;
            }

            (segment, &line[p..])
        },
        None => (line, "")
    }
}

fn trim_space<'a>(line: &'a str) -> &'a str {
    if line.len() == 0 {
        return line;
    }

    let mut p = 0;
    while line.char_at(p) == ' ' && p < line.len() - 1 {
        p += 1;
    }

    &line[p..]
}

fn parse_owned<'a>(line: &'a str) -> Result<IrcMessage<'static>, ()> {
    parse_into(line, |a| Cow::Owned(a.to_string()))
}

fn parse_slice<'a>(line: &'a str) -> Result<IrcMessage<'a>, ()> {
    parse_into(line, |a| Cow::Borrowed(a))
}

fn parse_into<'a, 'b, F>(line: &'a str, wrap: F) -> Result<IrcMessage<'b>, ()>
where F: Fn(&'a str) -> CowString<'b> {
    let mut message = IrcMessage::new_empty();

    // TAGS
    let line = if line.char_at(0) == '@' {
        let (tags, rest) = next_segment(&line[1..]);
        let raw_tags = tags.split(';');
        for tag in raw_tags {
            println!("{}", tag);
            if tag.contains_char('=') {
                let mut pair = tag.split('=');
                message.tags.insert(wrap(pair.next().unwrap()), wrap(pair.next().unwrap()));
            } else {
                message.tags.insert(wrap(tag), wrap("true"));
            }
        }
        rest
    } else {
        line
    };

    // PREFIX
    let line = if line.char_at(0) == ':' {
        let (prefix, rest) = next_segment(&line[1..]);
        message.prefix = Some(wrap(prefix));
        rest
    } else {
        line
    };

    // COMMAND
    let (command, line) = next_segment(line);
    message.command = Some(wrap(command));

    // PARAMS
    let mut rest = trim_space(line);
    while !rest.is_empty() {
        match next_segment(rest) {
            ("", _) => {
                break;
            }
            (_, _) if rest.char_at(0) == ':' => {
                message.params.push(wrap(&rest[1..]));
                break;
            }
            (last, "") => {
                message.params.push(wrap(last));
                break;
            }
            (next, tail) => {
                message.params.push(wrap(next));
                rest = tail;
            }
        }
    }

    return Ok(message);
}
<commit_msg>Remove unused allow(dead_code)<commit_after>#![feature(core, collections)]
use std::collections::hash_map::HashMap;
use std::borrow::Cow;
use std::string::CowString;

#[cfg(test)]
mod tests;

#[derive(Debug)]
pub struct IrcMessage<'a> {
    pub tags: HashMap<CowString<'a>, CowString<'a>>,
    pub prefix: Option<CowString<'a>>,
    pub command: Option<CowString<'a>>,
    pub params: Vec<CowString<'a>>
}

impl <'b> IrcMessage<'b> {
    pub fn new_empty<'a>() -> IrcMessage<'a> {
        IrcMessage {
            tags: HashMap::new(),
            prefix: None,
            command: None,
            params: Vec::new()
        }
    }

    /// Parse a message from a string to an owned `IrcMessage`.
    pub fn parse_owned<'a>(s: &'a str) -> Result<IrcMessage<'static>, ()> {
        return parse_owned(s);
    }

    /// Parse a message from a string to an `IrcMessage` that still refers
    /// to the original `str`.  Useful for minimizing allocations.
    pub fn parse_slice<'a>(s: &'a str) -> Result<IrcMessage<'a>, ()> {
        return parse_slice(s);
    }
}

fn next_segment<'a>(line: &'a str) -> (&'a str, &'a str) {
    match line.find(' ') {
        Some(n) => {
            if line.len() == 0 {
                return (line, line);
            }
            let segment = &line[..n];

            let mut p = n;

            while line.char_at(p) == ' ' && p < line.len() - 1 {
                p += 1;
            }

            (segment, &line[p..])
        },
        None => (line, "")
    }
}

fn trim_space<'a>(line: &'a str) -> &'a str {
    if line.len() == 0 {
        return line;
    }

    let mut p = 0;
    while line.char_at(p) == ' ' && p < line.len() - 1 {
        p += 1;
    }

    &line[p..]
}

fn parse_owned<'a>(line: &'a str) -> Result<IrcMessage<'static>, ()> {
    parse_into(line, |a| Cow::Owned(a.to_string()))
}

fn parse_slice<'a>(line: &'a str) -> Result<IrcMessage<'a>, ()> {
    parse_into(line, |a| Cow::Borrowed(a))
}

fn parse_into<'a, 'b, F>(line: &'a str, wrap: F) -> Result<IrcMessage<'b>, ()>
where F: Fn(&'a str) -> CowString<'b> {
    let mut message = IrcMessage::new_empty();

    // TAGS
    let line = if line.char_at(0) == '@' {
        let (tags, rest) = next_segment(&line[1..]);
        let raw_tags = tags.split(';');
        for tag in raw_tags {
            println!("{}", tag);
            if tag.contains_char('=') {
                let mut pair = tag.split('=');
                message.tags.insert(wrap(pair.next().unwrap()), wrap(pair.next().unwrap()));
            } else {
                message.tags.insert(wrap(tag), wrap("true"));
            }
        }
        rest
    } else {
        line
    };

    // PREFIX
    let line = if line.char_at(0) == ':' {
        let (prefix, rest) = next_segment(&line[1..]);
        message.prefix = Some(wrap(prefix));
        rest
    } else {
        line
    };

    // COMMAND
    let (command, line) = next_segment(line);
    message.command = Some(wrap(command));

    // PARAMS
    let mut rest = trim_space(line);
    while !rest.is_empty() {
        match next_segment(rest) {
            ("", _) => {
                break;
            }
            (_, _) if rest.char_at(0) == ':' => {
                message.params.push(wrap(&rest[1..]));
                break;
            }
            (last, "") => {
                message.params.push(wrap(last));
                break;
            }
            (next, tail) => {
                message.params.push(wrap(next));
                rest = tail;
            }
        }
    }

    return Ok(message);
}
<|endoftext|>


<commit_before>use crate::cargo::TestBinary;
use crate::config::*;
use crate::errors::*;
use crate::process_handling::*;
use crate::report::report_coverage;
use crate::source_analysis::LineAnalysis;
use crate::statemachine::*;
use crate::test_loader::*;
use crate::traces::*;
use log::{error, info, trace, warn};
use nix::unistd::*;
use std::collections::HashMap;
use std::env;
use std::ffi::CString;
use std::fs::create_dir_all;
use std::path::{Path, PathBuf};

pub mod breakpoint;
mod cargo;
pub mod config;
pub mod errors;
mod process_handling;
pub mod report;
mod source_analysis;
mod statemachine;
pub mod test_loader;
pub mod traces;

mod ptrace_control;

pub fn trace(configs: &[Config]) -> Result<TraceMap, RunError> {
    let mut tracemap = TraceMap::new();
    let mut tarpaulin_result = Ok(());

    for config in configs.iter() {
        if config.name == "report" {
            continue;
        }
        let tgt = config.target_dir();
        if !tgt.exists() {
            let create_dir_result = create_dir_all(&tgt);
            if let Err(e) = create_dir_result {
                warn!("Failed to create target-dir {}", e);
            }
        }
        match launch_tarpaulin(config) {
            Ok((t, r)) => {
                if r != 0 {
                    warn!("Test exit code: {}", r);
                }
                tracemap.merge(&t);
            }
            Err(e) => {
                error!("{}", e);
                tarpaulin_result = tarpaulin_result.and_then(|_| Err(e));
            }
        }
    }
    tracemap.dedup();
    tarpaulin_result.map(|_| tracemap)
}

pub fn run(configs: &[Config]) -> Result<(), RunError> {
    let tracemap = trace(configs)?;
    if configs.len() == 1 {
        report_coverage(&configs[0], &tracemap)?;
    } else if !configs.is_empty() {
        let mut reported = false;
        for c in configs.iter() {
            if c.name == "report" {
                reported = true;
                report_coverage(c, &tracemap)?;
            }
        }
        if !reported {
            report_coverage(&configs[0], &tracemap)?;
        }
    }

    Ok(())
}

/// Launches tarpaulin with the given configuration.
pub fn launch_tarpaulin(config: &Config) -> Result<(TraceMap, i32), RunError> {
    if !config.name.is_empty() {
        info!("Running config {}", config.name);
    }

    info!("Running Tarpaulin");

    let mut result = TraceMap::new();
    let mut return_code = 0i32;
    info!("Building project");
    let executables = cargo::get_tests(config)?;
    let project_analysis = source_analysis::get_line_analysis(config);
    for exe in &executables {
        let coverage = get_test_coverage(&exe, &project_analysis, config, false)?;
        if let Some(res) = coverage {
            result.merge(&res.0);
            return_code |= res.1;
        }
        if config.run_ignored && exe.run_type() == RunType::Tests {
            let coverage = get_test_coverage(&exe, &project_analysis, config, true)?;
            if let Some(res) = coverage {
                result.merge(&res.0);
                return_code |= res.1;
            }
        }
    }
    result.dedup();
    Ok((result, return_code))
}

/// Returns the coverage statistics for a test executable in the given workspace
pub fn get_test_coverage(
    test: &TestBinary,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
    ignored: bool,
) -> Result<Option<(TraceMap, i32)>, RunError> {
    if !test.path().exists() {
        return Ok(None);
    }
    if let Err(e) = limit_affinity() {
        warn!("Failed to set processor affinity {}", e);
    }
    match fork() {
        Ok(ForkResult::Parent { child }) => {
            match collect_coverage(test.path(), child, analysis, config) {
                Ok(t) => Ok(Some(t)),
                Err(e) => Err(RunError::TestCoverage(e.to_string())),
            }
        }
        Ok(ForkResult::Child) => {
            info!("Launching test");
            execute_test(test, ignored, config)?;
            Ok(None)
        }
        Err(err) => Err(RunError::TestCoverage(format!(
            "Failed to run test {}, Error: {}",
            test.path().display(),
            err.to_string()
        ))),
    }
}

/// Collects the coverage data from the launched test
fn collect_coverage(
    test_path: &Path,
    test: Pid,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
) -> Result<(TraceMap, i32), RunError> {
    let mut ret_code = 0;
    let mut traces = generate_tracemap(test_path, analysis, config)?;
    {
        trace!("Test PID is {}", test);
        let (mut state, mut data) = create_state_machine(test, &mut traces, config);
        loop {
            state = state.step(&mut data, config)?;
            if state.is_finished() {
                if let TestState::End(i) = state {
                    ret_code = i;
                }
                break;
            }
        }
    }
    Ok((traces, ret_code))
}

/// Launches the test executable
fn execute_test(test: &TestBinary, ignored: bool, config: &Config) -> Result<(), RunError> {
    let exec_path = CString::new(test.path().to_str().unwrap()).unwrap();
    info!("running {}", test.path().display());
    let _ = match test.manifest_dir() {
        Some(md) => env::set_current_dir(&md),
        None => env::set_current_dir(&config.root()),
    };

    let mut envars: Vec<CString> = Vec::new();

    for (key, value) in env::vars() {
        let mut temp = String::new();
        temp.push_str(key.as_str());
        temp.push('=');
        temp.push_str(value.as_str());
        envars.push(CString::new(temp).unwrap());
    }
    let mut argv = if ignored {
        vec![exec_path.clone(), CString::new("--ignored").unwrap()]
    } else {
        vec![exec_path.clone()]
    };
    if config.verbose {
        envars.push(CString::new("RUST_BACKTRACE=1").unwrap());
    }
    for s in &config.varargs {
        argv.push(CString::new(s.as_bytes()).unwrap_or_default());
    }

    if let Some(s) = test.pkg_name() {
        envars.push(CString::new(format!("CARGO_PKG_NAME={}", s)).unwrap_or_default());
    }
    if let Some(s) = test.pkg_version() {
        envars.push(CString::new(format!("CARGO_PKG_VERSION={}", s)).unwrap_or_default());
    }
    if let Some(s) = test.pkg_authors() {
        envars.push(CString::new(format!("CARGO_PKG_AUTHORS={}", s.join(":"))).unwrap_or_default());
    }
    if let Some(s) = test.manifest_dir() {
        envars
            .push(CString::new(format!("CARGO_MANIFEST_DIR={}", s.display())).unwrap_or_default());
    }

    execute(exec_path, &argv, envars.as_slice())
}
<commit_msg>Return test error code to user.<commit_after>use crate::cargo::TestBinary;
use crate::config::*;
use crate::errors::*;
use crate::process_handling::*;
use crate::report::report_coverage;
use crate::source_analysis::LineAnalysis;
use crate::statemachine::*;
use crate::test_loader::*;
use crate::traces::*;
use log::{error, info, trace, warn};
use nix::unistd::*;
use std::collections::HashMap;
use std::env;
use std::ffi::CString;
use std::fs::create_dir_all;
use std::path::{Path, PathBuf};

pub mod breakpoint;
mod cargo;
pub mod config;
pub mod errors;
mod process_handling;
pub mod report;
mod source_analysis;
mod statemachine;
pub mod test_loader;
pub mod traces;

mod ptrace_control;

pub fn trace(configs: &[Config]) -> Result<TraceMap, RunError> {
    let mut tracemap = TraceMap::new();
    let mut tarpaulin_result = Ok(());
    let mut ret = 0i32;

    for config in configs.iter() {
        if config.name == "report" {
            continue;
        }
        let tgt = config.target_dir();
        if !tgt.exists() {
            let create_dir_result = create_dir_all(&tgt);
            if let Err(e) = create_dir_result {
                warn!("Failed to create target-dir {}", e);
            }
        }
        match launch_tarpaulin(config) {
            Ok((t, r)) => {
                ret |= r;
                tracemap.merge(&t);
            }
            Err(e) => {
                error!("{}", e);
                tarpaulin_result = tarpaulin_result.and_then(|_| Err(e));
            }
        }
    }
    tracemap.dedup();

    if ret == 0 {
        tarpaulin_result.map(|_| tracemap)
    } else {
        Err(RunError::TestFailed)
    }
}

pub fn run(configs: &[Config]) -> Result<(), RunError> {
    let tracemap = trace(configs)?;
    if configs.len() == 1 {
        report_coverage(&configs[0], &tracemap)?;
    } else if !configs.is_empty() {
        let mut reported = false;
        for c in configs.iter() {
            if c.name == "report" {
                reported = true;
                report_coverage(c, &tracemap)?;
            }
        }
        if !reported {
            report_coverage(&configs[0], &tracemap)?;
        }
    }

    Ok(())
}

/// Launches tarpaulin with the given configuration.
pub fn launch_tarpaulin(config: &Config) -> Result<(TraceMap, i32), RunError> {
    if !config.name.is_empty() {
        info!("Running config {}", config.name);
    }

    info!("Running Tarpaulin");

    let mut result = TraceMap::new();
    let mut return_code = 0i32;
    info!("Building project");
    let executables = cargo::get_tests(config)?;
    let project_analysis = source_analysis::get_line_analysis(config);
    for exe in &executables {
        let coverage = get_test_coverage(&exe, &project_analysis, config, false)?;
        if let Some(res) = coverage {
            result.merge(&res.0);
            return_code |= res.1;
        }
        if config.run_ignored && exe.run_type() == RunType::Tests {
            let coverage = get_test_coverage(&exe, &project_analysis, config, true)?;
            if let Some(res) = coverage {
                result.merge(&res.0);
                return_code |= res.1;
            }
        }
    }
    result.dedup();
    Ok((result, return_code))
}

/// Returns the coverage statistics for a test executable in the given workspace
pub fn get_test_coverage(
    test: &TestBinary,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
    ignored: bool,
) -> Result<Option<(TraceMap, i32)>, RunError> {
    if !test.path().exists() {
        return Ok(None);
    }
    if let Err(e) = limit_affinity() {
        warn!("Failed to set processor affinity {}", e);
    }
    match fork() {
        Ok(ForkResult::Parent { child }) => {
            match collect_coverage(test.path(), child, analysis, config) {
                Ok(t) => Ok(Some(t)),
                Err(e) => Err(RunError::TestCoverage(e.to_string())),
            }
        }
        Ok(ForkResult::Child) => {
            info!("Launching test");
            execute_test(test, ignored, config)?;
            Ok(None)
        }
        Err(err) => Err(RunError::TestCoverage(format!(
            "Failed to run test {}, Error: {}",
            test.path().display(),
            err.to_string()
        ))),
    }
}

/// Collects the coverage data from the launched test
fn collect_coverage(
    test_path: &Path,
    test: Pid,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
) -> Result<(TraceMap, i32), RunError> {
    let mut ret_code = 0;
    let mut traces = generate_tracemap(test_path, analysis, config)?;
    {
        trace!("Test PID is {}", test);
        let (mut state, mut data) = create_state_machine(test, &mut traces, config);
        loop {
            state = state.step(&mut data, config)?;
            if state.is_finished() {
                if let TestState::End(i) = state {
                    ret_code = i;
                }
                break;
            }
        }
    }
    Ok((traces, ret_code))
}

/// Launches the test executable
fn execute_test(test: &TestBinary, ignored: bool, config: &Config) -> Result<(), RunError> {
    let exec_path = CString::new(test.path().to_str().unwrap()).unwrap();
    info!("running {}", test.path().display());
    let _ = match test.manifest_dir() {
        Some(md) => env::set_current_dir(&md),
        None => env::set_current_dir(&config.root()),
    };

    let mut envars: Vec<CString> = Vec::new();

    for (key, value) in env::vars() {
        let mut temp = String::new();
        temp.push_str(key.as_str());
        temp.push('=');
        temp.push_str(value.as_str());
        envars.push(CString::new(temp).unwrap());
    }
    let mut argv = if ignored {
        vec![exec_path.clone(), CString::new("--ignored").unwrap()]
    } else {
        vec![exec_path.clone()]
    };
    if config.verbose {
        envars.push(CString::new("RUST_BACKTRACE=1").unwrap());
    }
    for s in &config.varargs {
        argv.push(CString::new(s.as_bytes()).unwrap_or_default());
    }

    if let Some(s) = test.pkg_name() {
        envars.push(CString::new(format!("CARGO_PKG_NAME={}", s)).unwrap_or_default());
    }
    if let Some(s) = test.pkg_version() {
        envars.push(CString::new(format!("CARGO_PKG_VERSION={}", s)).unwrap_or_default());
    }
    if let Some(s) = test.pkg_authors() {
        envars.push(CString::new(format!("CARGO_PKG_AUTHORS={}", s.join(":"))).unwrap_or_default());
    }
    if let Some(s) = test.manifest_dir() {
        envars
            .push(CString::new(format!("CARGO_MANIFEST_DIR={}", s.display())).unwrap_or_default());
    }

    execute(exec_path, &argv, envars.as_slice())
}
<|endoftext|>


<commit_before>#![feature(collections, unboxed_closures, core)]
extern crate itertools;
extern crate rustc_serialize;

use std::collections::{BTreeMap, HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use std::iter;
use std::ops;

use itertools::{GroupBy, Itertools};

/// A Document contains an id and content.
/// Hashing and equality are based only on the id field.
#[derive(Clone, Eq, Debug, RustcEncodable, RustcDecodable)]
pub struct Document {
    id: String,
    content: String,
}

impl Document {
    /// Construct a new Document from an id and content.
    /// Both two arguments can be anything that can be turned into a String.
    pub fn new<S, T>(id: S, content: T) -> Document
        where S: Into<String>,
              T: Into<String>
    {
        Document { id: id.into(), content: content.into(), }
    }

    pub fn id(&self) -> &str {
        &self.id
    }

    pub fn content(&self) -> &str {
        &self.content
    }
}

impl Hash for Document {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write(self.id.as_bytes());
    }
}

impl PartialEq<Document> for Document {
    fn eq(&self, other: &Document) -> bool {
        self.id == other.id
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct IndexedDocument {
    pub doc: Arc<Document>,
    pub highlighted: (usize, usize),
}

fn ngrams((_, chars): (bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams> {
    (1..chars.len() + 1).map(Ngrams::new(chars))
}

fn not_whitespace(&(is_whitespace, _): &(bool, Vec<(usize, char)>)) -> bool {
    !is_whitespace
}

fn is_whitespace(&(_, c): &(usize, char)) -> bool {
    c.is_whitespace()
}

struct Ngrams {
    chars: Vec<(usize, char)>
}

impl Ngrams {
    fn new(chars: Vec<(usize, char)>) -> Ngrams {
        Ngrams { chars: chars }
    }
}

impl Fn<(usize,)> for Ngrams {
    extern "rust-call" fn call(&self, (to,): (usize,)) -> (String, (usize, usize)) {
        let word = self.chars[..to].iter().flat_map(|&(_, c)| c.to_lowercase()).collect();
        let start = self.chars[0].0;
        let (last_idx, last_char) = self.chars[to - 1];
        let finish = last_idx + last_char.len_utf8();
        (word, (start, finish))
    }
}

impl FnMut<(usize,)> for Ngrams {
    extern "rust-call" fn call_mut(&mut self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

impl FnOnce<(usize,)> for Ngrams {
    type Output = (String, (usize, usize));
    extern "rust-call" fn call_once(self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

fn analyze_doc(doc: &str)
-> iter::FlatMap<
    iter::Filter<
        GroupBy<bool, std::str::CharIndices, fn(&(usize, char)) -> bool>,
        fn(&(bool, Vec<(usize, char)>)) -> bool>,
    iter::Map<ops::Range<usize>, Ngrams>,
    fn((bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams>>
{
    doc.char_indices()
        .group_by(is_whitespace as fn(&(usize, char)) -> bool)
        .filter(not_whitespace as fn(&(bool, Vec<(usize, char)>)) -> bool)
        .flat_map(ngrams)
}

/// A basic implementation of an `Index`, the inverted index is a data structure that maps
/// from words to sets of Documents.
#[derive(Debug)]
pub struct InvertedIndex {
    index: BTreeMap<String, HashSet<IndexedDocument>>,
    docs: BTreeMap<String, Arc<Document>>,
}

impl InvertedIndex {
    pub fn new() -> InvertedIndex {
        InvertedIndex {
            index: BTreeMap::new(),
            docs: BTreeMap::new(),
        }
    }

    /// A basic implementation of index, splits the document's content into whitespace-separated
    /// words, and inserts each word-document pair into the map.
    pub fn index(&mut self, doc: Document) {
        let doc = Arc::new(doc);
        let analyzed  = analyze_doc(doc.content());
        let previous_version = self.docs.insert(doc.id.clone(), doc.clone());
        if let Some(previous_version) = previous_version {
            let previous_analyzed = analyze_doc(previous_version.content());
            for (ngram, highlights) in previous_analyzed {
                let is_empty = {
                    let docs_for_ngram = self.index.get_mut(&ngram).unwrap();
                    docs_for_ngram.remove(&IndexedDocument { doc: doc.clone(), highlighted: highlights });
                    docs_for_ngram.is_empty()
                };
                if is_empty {
                    self.index.remove(&ngram);
                }
            }
        }

        for (ngram, highlighted) in analyzed {
            self.index.entry(ngram).or_insert_with(|| HashSet::new())
                .insert(IndexedDocument { doc: doc.clone(), highlighted: highlighted });
        }
    }

    /// A basic search implementation that splits the query's content into whitespace-separated
    /// words, looks up the set of Documents for each word, and then concatenates the sets.
    pub fn search(&self, query: &str) -> Vec<SearchResult> {
        let map = query.split_whitespace()
            .flat_map(|word| self.index.get(&word.to_lowercase()))
            .flat_map(|doc| doc)
            .cloned()
            .fold(HashMap::new(), |mut map, search_result| {
                map.entry(search_result.doc)
                    .or_insert(Vec::new())
                    .push(search_result.highlighted);
                map
            });
        let mut results: Vec<_> = map.into_iter()
            .map(SearchResult::new_)
            .collect();
        results.sort_by(|result1, result2| result2.score.partial_cmp(&result1.score).unwrap());
        results
    }
}

#[derive(Clone, Debug, PartialEq, RustcEncodable)]
pub struct SearchResult {
    doc: Arc<Document>,
    highlights: Vec<(usize, usize)>,
    score: f64,
}

impl SearchResult {
    fn new_((doc, highlights): (Arc<Document>, Vec<(usize, usize)>)) -> SearchResult {
        SearchResult::new(doc, highlights)
    }

    fn new(doc: Arc<Document>, mut highlights: Vec<(usize, usize)>) -> SearchResult {
        highlights.sort();
        SearchResult {
            score: highlights.iter().map(|&(begin, end)| end - begin).sum::<usize>() as f64 / doc.content.len() as f64,
            doc: doc,
            highlights: highlights,
        }
    }

    pub fn doc(&self) -> &Arc<Document> {
        &self.doc
    }

    pub fn highlights(&self) -> &Vec<(usize, usize)> {
        &self.highlights
    }

    pub fn highlighted_content(&self) -> String {
        let &SearchResult {ref doc, ref highlights, .. } = self;
        let content = doc.content();
        let mut begin_idx = 0;
        let mut parts = vec![];
        for &(begin, end) in highlights {
            parts.push(&content[begin_idx..begin]);
            parts.push("");
            parts.push(&content[begin..end]);
            parts.push("");
            begin_idx = end;
        }
        parts.push(&content[begin_idx..]);
        parts.into_iter().join("")
    }
}

#[test]
fn test_search1() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    index.index(doc1.clone());
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 15)])
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!("learn to program in rust today", expected[0].highlighted_content());
}

#[test]
fn test_ngrams() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 15)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!("learn to program in rust today", expected[0].highlighted_content());

}

#[test]
fn test_search2() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("2", "what to do today");
    let doc2 = Document::new("3", "hey today");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(5, 7), (11, 13)]),
        SearchResult::new(Arc::new(doc2), vec![(4, 6)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!(expected[0].highlighted_content(), "what to do today");
}

#[test]
fn test_unicode() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    index.index(doc.clone());
    let to_search = "å";
    let search_results = index.search(to_search);
    let &SearchResult { ref doc, ref highlights, .. } = search_results.iter().next().unwrap();
    let (begin, end) = highlights[0];
    assert_eq!(&doc.content()[begin..end], to_search);
}

#[test]
fn test_update_doc() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    index.index(doc);
    let doc = Document::new("0", "different");
    index.index(doc);
    let search_results = index.search("å");
    assert!(search_results.is_empty());
    assert_eq!(index.docs.len(), 1);
}

#[test]
fn test_ranking() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "beat");
    index.index(doc.clone());
    let doc2 = Document::new("1", "beast");
    index.index(doc2.clone());
    let search_results = index.search("be");
    assert_eq!(index.docs.len(), 2);
    assert_eq!(&*search_results.into_iter().next().unwrap().doc, &doc);
}
<commit_msg>Add the highlighted string to the search result instead of making it a method.<commit_after>#![feature(collections, unboxed_closures, core)]
extern crate itertools;
extern crate rustc_serialize;

use std::collections::{BTreeMap, HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use std::iter;
use std::ops;

use itertools::{GroupBy, Itertools};

/// A Document contains an id and content.
/// Hashing and equality are based only on the id field.
#[derive(Clone, Eq, Debug, RustcEncodable, RustcDecodable)]
pub struct Document {
    id: String,
    content: String,
}

impl Document {
    /// Construct a new Document from an id and content.
    /// Both two arguments can be anything that can be turned into a String.
    pub fn new<S, T>(id: S, content: T) -> Document
        where S: Into<String>,
              T: Into<String>
    {
        Document { id: id.into(), content: content.into(), }
    }

    pub fn id(&self) -> &str {
        &self.id
    }

    pub fn content(&self) -> &str {
        &self.content
    }
}

impl Hash for Document {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write(self.id.as_bytes());
    }
}

impl PartialEq<Document> for Document {
    fn eq(&self, other: &Document) -> bool {
        self.id == other.id
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct IndexedDocument {
    pub doc: Arc<Document>,
    pub highlighted: (usize, usize),
}

fn ngrams((_, chars): (bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams> {
    (1..chars.len() + 1).map(Ngrams::new(chars))
}

fn not_whitespace(&(is_whitespace, _): &(bool, Vec<(usize, char)>)) -> bool {
    !is_whitespace
}

fn is_whitespace(&(_, c): &(usize, char)) -> bool {
    c.is_whitespace()
}

struct Ngrams {
    chars: Vec<(usize, char)>
}

impl Ngrams {
    fn new(chars: Vec<(usize, char)>) -> Ngrams {
        Ngrams { chars: chars }
    }
}

impl Fn<(usize,)> for Ngrams {
    extern "rust-call" fn call(&self, (to,): (usize,)) -> (String, (usize, usize)) {
        let word = self.chars[..to].iter().flat_map(|&(_, c)| c.to_lowercase()).collect();
        let start = self.chars[0].0;
        let (last_idx, last_char) = self.chars[to - 1];
        let finish = last_idx + last_char.len_utf8();
        (word, (start, finish))
    }
}

impl FnMut<(usize,)> for Ngrams {
    extern "rust-call" fn call_mut(&mut self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

impl FnOnce<(usize,)> for Ngrams {
    type Output = (String, (usize, usize));
    extern "rust-call" fn call_once(self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

fn analyze_doc(doc: &str)
-> iter::FlatMap<
    iter::Filter<
        GroupBy<bool, std::str::CharIndices, fn(&(usize, char)) -> bool>,
        fn(&(bool, Vec<(usize, char)>)) -> bool>,
    iter::Map<ops::Range<usize>, Ngrams>,
    fn((bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams>>
{
    doc.char_indices()
        .group_by(is_whitespace as fn(&(usize, char)) -> bool)
        .filter(not_whitespace as fn(&(bool, Vec<(usize, char)>)) -> bool)
        .flat_map(ngrams)
}

/// A basic implementation of an `Index`, the inverted index is a data structure that maps
/// from words to sets of Documents.
#[derive(Debug)]
pub struct InvertedIndex {
    index: BTreeMap<String, HashSet<IndexedDocument>>,
    docs: BTreeMap<String, Arc<Document>>,
}

impl InvertedIndex {
    pub fn new() -> InvertedIndex {
        InvertedIndex {
            index: BTreeMap::new(),
            docs: BTreeMap::new(),
        }
    }

    /// A basic implementation of index, splits the document's content into whitespace-separated
    /// words, and inserts each word-document pair into the map.
    pub fn index(&mut self, doc: Document) {
        let doc = Arc::new(doc);
        let analyzed  = analyze_doc(doc.content());
        let previous_version = self.docs.insert(doc.id.clone(), doc.clone());
        if let Some(previous_version) = previous_version {
            let previous_analyzed = analyze_doc(previous_version.content());
            for (ngram, highlights) in previous_analyzed {
                let is_empty = {
                    let docs_for_ngram = self.index.get_mut(&ngram).unwrap();
                    docs_for_ngram.remove(&IndexedDocument { doc: doc.clone(), highlighted: highlights });
                    docs_for_ngram.is_empty()
                };
                if is_empty {
                    self.index.remove(&ngram);
                }
            }
        }

        for (ngram, highlighted) in analyzed {
            self.index.entry(ngram).or_insert_with(|| HashSet::new())
                .insert(IndexedDocument { doc: doc.clone(), highlighted: highlighted });
        }
    }

    /// A basic search implementation that splits the query's content into whitespace-separated
    /// words, looks up the set of Documents for each word, and then concatenates the sets.
    pub fn search(&self, query: &str) -> Vec<SearchResult> {
        let map = query.split_whitespace()
            .flat_map(|word| self.index.get(&word.to_lowercase()))
            .flat_map(|doc| doc)
            .cloned()
            .fold(HashMap::new(), |mut map, search_result| {
                map.entry(search_result.doc)
                    .or_insert(Vec::new())
                    .push(search_result.highlighted);
                map
            });
        let mut results: Vec<_> = map.into_iter()
            .map(SearchResult::new_)
            .collect();
        results.sort_by(|result1, result2| result2.score.partial_cmp(&result1.score).unwrap());
        results
    }
}

#[derive(Clone, Debug, PartialEq, RustcEncodable)]
pub struct SearchResult {
    pub doc: Arc<Document>,
    pub highlights: Vec<(usize, usize)>,
    pub highlighted: String,
    pub score: f64,
}

impl SearchResult {
    fn new_((doc, highlights): (Arc<Document>, Vec<(usize, usize)>)) -> SearchResult {
        SearchResult::new(doc, highlights)
    }

    fn new(doc: Arc<Document>, mut highlights: Vec<(usize, usize)>) -> SearchResult {
        SearchResult {
            score: highlights.iter().map(|&(begin, end)| end - begin).sum::<usize>() as f64 / doc.content.len() as f64,
            highlighted: SearchResult::highlighted_content(&doc.content, &mut highlights),
            doc: doc,
            highlights: highlights,
        }
    }

    fn highlighted_content(content: &str, highlights: &mut [(usize, usize)]) -> String {
        highlights.sort();
        let mut begin_idx = 0;
        let mut parts = vec![];
        for &mut (begin, end) in highlights {
            parts.push(&content[begin_idx..begin]);
            parts.push("");
            parts.push(&content[begin..end]);
            parts.push("");
            begin_idx = end;
        }
        parts.push(&content[begin_idx..]);
        parts.into_iter().join("")
    }
}

#[test]
fn test_search1() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    index.index(doc1.clone());
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 15)])
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!("learn to program in rust today", expected[0].highlighted);
}

#[test]
fn test_ngrams() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 15)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!("learn to program in rust today", expected[0].highlighted);

}

#[test]
fn test_search2() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("2", "what to do today");
    let doc2 = Document::new("3", "hey today");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(5, 7), (11, 13)]),
        SearchResult::new(Arc::new(doc2), vec![(4, 6)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!(expected[0].highlighted, "what to do today");
}

#[test]
fn test_unicode() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    index.index(doc.clone());
    let to_search = "å";
    let search_results = index.search(to_search);
    let &SearchResult { ref doc, ref highlights, .. } = search_results.iter().next().unwrap();
    let (begin, end) = highlights[0];
    assert_eq!(&doc.content()[begin..end], to_search);
}

#[test]
fn test_update_doc() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    index.index(doc);
    let doc = Document::new("0", "different");
    index.index(doc);
    let search_results = index.search("å");
    assert!(search_results.is_empty());
    assert_eq!(index.docs.len(), 1);
}

#[test]
fn test_ranking() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "beat");
    index.index(doc.clone());
    let doc2 = Document::new("1", "beast");
    index.index(doc2.clone());
    let search_results = index.search("be");
    assert_eq!(index.docs.len(), 2);
    assert_eq!(&*search_results.into_iter().next().unwrap().doc, &doc);
}
<|endoftext|>


<commit_before>#![crate_name = "bytes"]
#![unstable]

#![feature(core)]
#![feature(alloc)]
#![feature(unsafe_no_drop_flag)]

pub use byte_buf::{ByteBuf, ROByteBuf, MutByteBuf};
pub use byte_str::{SeqByteStr, SmallByteStr, SmallByteStrBuf};
pub use bytes::Bytes;
pub use ring::{RingBuf, RingBufReader, RingBufWriter};
pub use rope::Rope;
pub use slice::{SliceBuf, MutSliceBuf};

use std::{cmp, io, ops, ptr, u32};

extern crate core;

mod alloc;
mod byte_buf;
mod byte_str;
mod bytes;
mod ring;
mod rope;
mod slice;

pub mod traits {
    //! All traits are re-exported here to allow glob imports.
    pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr};
}

const MAX_CAPACITY: usize = u32::MAX as usize;

/// A trait for values that provide sequential read access to bytes.
pub trait Buf {

    /// Returns the number of bytes that can be accessed from the Buf
    fn remaining(&self) -> usize;

    /// Returns a slice starting at the current Buf position and of length
    /// between 0 and `Buf::remaining()`.
    fn bytes<'a>(&'a self) -> &'a [u8];

    /// Advance the internal cursor of the Buf
    fn advance(&mut self, cnt: usize);

    /// Returns true if there are any more bytes to consume
    fn has_remaining(&self) -> bool {
        self.remaining() > 0
    }

    /// Read bytes from the `Buf` into the given slice and advance the cursor by
    /// the number of bytes read.
    ///
    /// If there are fewer bytes remaining than is needed to satisfy the
    /// request (aka `dst.len()` > self.remaining()`), then
    /// `Err(BufError::Overflow)` is returned.
    ///
    /// ```
    /// use bytes::{SliceBuf, Buf};
    ///
    /// let mut buf = SliceBuf::wrap(b"hello world");
    /// let mut dst = [0; 5];
    ///
    /// buf.read_slice(&mut dst);
    /// assert_eq!(b"hello", dst);
    /// assert_eq!(6, buf.remaining());
    /// ```
    fn read_slice(&mut self, dst: &mut [u8]) -> usize {
        let mut off = 0;
        let len = cmp::min(dst.len(), self.remaining());

        while off < len {
            let mut cnt;

            unsafe {
                let src = self.bytes();
                cnt = cmp::min(src.len(), len - off);

                ptr::copy_nonoverlapping_memory(
                    dst[off..].as_mut_ptr(), src.as_ptr(), cnt);

                off += src.len();
            }

            self.advance(cnt);
        }

        len
    }

    /// Read a single byte from the `Buf`
    fn read_byte(&mut self) -> Option<u8> {
        let mut dst = [0];

        if self.read_slice(&mut dst) == 0 {
            return None;
        }

        Some(dst[0])
    }
}

/// An extension trait providing extra functions applicable to all `Buf` values.
pub trait BufExt {

    /// Read bytes from this Buf into the given sink and advance the cursor by
    /// the number of bytes read.
    fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error>;
}

/// A trait for values that provide sequential write access to bytes.
pub trait MutBuf : Sized {

    /// Returns the number of bytes that can be accessed from the Buf
    fn remaining(&self) -> usize;

    /// Advance the internal cursor of the Buf
    fn advance(&mut self, cnt: usize);

    /// Returns true if there are any more bytes to consume
    fn has_remaining(&self) -> bool {
        self.remaining() > 0
    }

    /// Returns a mutable slice starting at the current Buf position and of
    /// length between 0 and `Buf::remaining()`.
    fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8];

    /// Read bytes from this Buf into the given slice and advance the cursor by
    /// the number of bytes read.
    ///
    /// If there are fewer bytes remaining than is needed to satisfy the
    /// request (aka `dst.len()` > self.remaining()`), then
    /// `Err(BufError::Overflow)` is returned.
    ///
    /// ```
    /// use bytes::{MutSliceBuf, Buf, MutBuf};
    ///
    /// let mut dst = [0; 6];
    ///
    /// {
    ///     let mut buf = MutSliceBuf::wrap(&mut dst);
    ///     buf.write_slice(b"hello");
    ///
    ///     assert_eq!(1, buf.remaining());
    /// }
    ///
    /// assert_eq!(b"hello\0", dst);
    /// ```
    fn write_slice(&mut self, src: &[u8]) -> usize {
        let mut off = 0;
        let len = cmp::min(src.len(), self.remaining());

        while off < len {
            let mut cnt;

            unsafe {
                let dst = self.mut_bytes();
                cnt = cmp::min(dst.len(), len - off);

                ptr::copy_nonoverlapping_memory(
                    dst.as_mut_ptr(), src[off..].as_ptr(), cnt);

                off += cnt;
            }

            self.advance(cnt);
        }

        len
    }

    /// Write a single byte to the `MuBuf`
    fn write_byte(&mut self, byte: u8) -> bool {
        let src = [byte];

        if self.write_slice(&src) == 0 {
            return false;
        }

        true
    }
}

/// An extension trait providing extra functions applicable to all `MutBuf` values.
pub trait MutBufExt {

    /// Write bytes from the given source into the current `MutBuf` and advance
    /// the cursor by the number of bytes written.
    fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error>;
}

/*
 *
 * ===== ByteStr =====
 *
 */

/// An immutable sequence of bytes. Operations will not mutate the original
/// value. Since only immutable access is permitted, operations do not require
/// copying (though, sometimes copying will happen as an optimization).
pub trait ByteStr : Clone + Sized + Send + Sync + ops::Index<usize, Output=u8> {

    // Until HKT lands, the buf must be bound by 'static
    type Buf: Buf+'static;

    /// Returns a read-only `Buf` for accessing the byte contents of the
    /// `ByteStr`.
    fn buf(&self) -> Self::Buf;

    /// Returns a new `Bytes` value representing the concatenation of `self`
    /// with the given `Bytes`.
    fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes;

    /// Returns the number of bytes in the ByteStr
    fn len(&self) -> usize;

    /// Returns true if the length of the `ByteStr` is 0
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a new ByteStr value containing the byte range between `begin`
    /// (inclusive) and `end` (exclusive)
    fn slice(&self, begin: usize, end: usize) -> Bytes;

    /// Returns a new ByteStr value containing the byte range starting from
    /// `begin` (inclusive) to the end of the byte str.
    ///
    /// Equivalent to `bytes.slice(begin, bytes.len())`
    fn slice_from(&self, begin: usize) -> Bytes {
        self.slice(begin, self.len())
    }

    /// Returns a new ByteStr value containing the byte range from the start up
    /// to `end` (exclusive).
    ///
    /// Equivalent to `bytes.slice(0, end)`
    fn slice_to(&self, end: usize) -> Bytes {
        self.slice(0, end)
    }

    /// Divides the value into two `Bytes` at the given index.
    ///
    /// The first will contain all bytes from `[0, mid]` (excluding the index
    /// `mid` itself) and the second will contain all indices from `[mid, len)`
    /// (excluding the index `len` itself).
    ///
    /// Panics if `mid > len`.
    fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
        (self.slice_to(mid), self.slice_from(mid))
    }

    /// Consumes the value and returns a `Bytes` instance containing
    /// identical bytes
    fn to_bytes(self) -> Bytes;
}

/*
 *
 * ===== *Ext impls =====
 *
 */

impl<B: Buf> BufExt for B {
    fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error> {
        dst.sink(self)
    }
}

impl<B: MutBuf> MutBufExt for B {
    fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> {
        src.fill(self)
    }
}

/*
 *
 * ===== Sink / Source =====
 *
 */

/// A value that reads bytes from a Buf into itself
pub trait Sink {
    type Error;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}

/// A value that writes bytes from itself into a `MutBuf`.
pub trait Source {
    type Error;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}

impl<'a> Sink for &'a mut [u8] {
    type Error = BufError;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.read_slice(self))
    }
}

impl<'a> Sink for &'a mut Vec<u8> {
    type Error = BufError;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
        use std::slice;

        let rem = buf.remaining();
        let cap = self.capacity();
        let len = rem - cap;

        // Ensure that the vec is big enough
        if cap < rem {
            self.reserve(len);
        }

        unsafe {
            {
                let dst = self.as_mut_slice();
                buf.read_slice(slice::from_raw_parts_mut(dst.as_mut_ptr(), rem));
            }

            self.set_len(rem);
        }

        Ok(len)
    }
}

impl<'a> Source for &'a [u8] {
    type Error = BufError;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.write_slice(self))
    }
}

impl<'a> Source for &'a Vec<u8> {
    type Error = BufError;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.write_slice(self.as_slice()))
    }
}

impl<'a> Source for &'a Bytes {
    type Error = BufError;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
        unimplemented!();
    }
}

impl<'a> Source for &'a mut (io::Read+'a) {
    type Error = io::Error;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, io::Error> {
        unimplemented!();
    }
}

impl<'a> Source for &'a mut (Iterator<Item=u8>+'a) {
    type Error = BufError;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
        unimplemented!();
    }
}

/*
 *
 * ===== Buf impls =====
 *
 */

impl Buf for Box<Buf+'static> {
    fn remaining(&self) -> usize {
        (**self).remaining()
    }

    fn bytes(&self) -> &[u8] {
        (**self).bytes()
    }

    fn advance(&mut self, cnt: usize) {
        (**self).advance(cnt);
    }

    fn read_slice(&mut self, dst: &mut [u8]) -> usize {
        (**self).read_slice(dst)
    }
}

/*
 *
 * ===== BufError  =====
 *
 */

#[derive(Copy, Debug)]
pub enum BufError {
    Underflow,
    Overflow,
}
<commit_msg>Add io feature<commit_after>#![crate_name = "bytes"]
#![unstable]

#![feature(alloc, core, io, unsafe_no_drop_flag)]

pub use byte_buf::{ByteBuf, ROByteBuf, MutByteBuf};
pub use byte_str::{SeqByteStr, SmallByteStr, SmallByteStrBuf};
pub use bytes::Bytes;
pub use ring::{RingBuf, RingBufReader, RingBufWriter};
pub use rope::Rope;
pub use slice::{SliceBuf, MutSliceBuf};

use std::{cmp, io, ops, ptr, u32};

extern crate core;

mod alloc;
mod byte_buf;
mod byte_str;
mod bytes;
mod ring;
mod rope;
mod slice;

pub mod traits {
    //! All traits are re-exported here to allow glob imports.
    pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr};
}

const MAX_CAPACITY: usize = u32::MAX as usize;

/// A trait for values that provide sequential read access to bytes.
pub trait Buf {

    /// Returns the number of bytes that can be accessed from the Buf
    fn remaining(&self) -> usize;

    /// Returns a slice starting at the current Buf position and of length
    /// between 0 and `Buf::remaining()`.
    fn bytes<'a>(&'a self) -> &'a [u8];

    /// Advance the internal cursor of the Buf
    fn advance(&mut self, cnt: usize);

    /// Returns true if there are any more bytes to consume
    fn has_remaining(&self) -> bool {
        self.remaining() > 0
    }

    /// Read bytes from the `Buf` into the given slice and advance the cursor by
    /// the number of bytes read.
    ///
    /// If there are fewer bytes remaining than is needed to satisfy the
    /// request (aka `dst.len()` > self.remaining()`), then
    /// `Err(BufError::Overflow)` is returned.
    ///
    /// ```
    /// use bytes::{SliceBuf, Buf};
    ///
    /// let mut buf = SliceBuf::wrap(b"hello world");
    /// let mut dst = [0; 5];
    ///
    /// buf.read_slice(&mut dst);
    /// assert_eq!(b"hello", dst);
    /// assert_eq!(6, buf.remaining());
    /// ```
    fn read_slice(&mut self, dst: &mut [u8]) -> usize {
        let mut off = 0;
        let len = cmp::min(dst.len(), self.remaining());

        while off < len {
            let mut cnt;

            unsafe {
                let src = self.bytes();
                cnt = cmp::min(src.len(), len - off);

                ptr::copy_nonoverlapping_memory(
                    dst[off..].as_mut_ptr(), src.as_ptr(), cnt);

                off += src.len();
            }

            self.advance(cnt);
        }

        len
    }

    /// Read a single byte from the `Buf`
    fn read_byte(&mut self) -> Option<u8> {
        let mut dst = [0];

        if self.read_slice(&mut dst) == 0 {
            return None;
        }

        Some(dst[0])
    }
}

/// An extension trait providing extra functions applicable to all `Buf` values.
pub trait BufExt {

    /// Read bytes from this Buf into the given sink and advance the cursor by
    /// the number of bytes read.
    fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error>;
}

/// A trait for values that provide sequential write access to bytes.
pub trait MutBuf : Sized {

    /// Returns the number of bytes that can be accessed from the Buf
    fn remaining(&self) -> usize;

    /// Advance the internal cursor of the Buf
    fn advance(&mut self, cnt: usize);

    /// Returns true if there are any more bytes to consume
    fn has_remaining(&self) -> bool {
        self.remaining() > 0
    }

    /// Returns a mutable slice starting at the current Buf position and of
    /// length between 0 and `Buf::remaining()`.
    fn mut_bytes<'a>(&'a mut self) -> &'a mut [u8];

    /// Read bytes from this Buf into the given slice and advance the cursor by
    /// the number of bytes read.
    ///
    /// If there are fewer bytes remaining than is needed to satisfy the
    /// request (aka `dst.len()` > self.remaining()`), then
    /// `Err(BufError::Overflow)` is returned.
    ///
    /// ```
    /// use bytes::{MutSliceBuf, Buf, MutBuf};
    ///
    /// let mut dst = [0; 6];
    ///
    /// {
    ///     let mut buf = MutSliceBuf::wrap(&mut dst);
    ///     buf.write_slice(b"hello");
    ///
    ///     assert_eq!(1, buf.remaining());
    /// }
    ///
    /// assert_eq!(b"hello\0", dst);
    /// ```
    fn write_slice(&mut self, src: &[u8]) -> usize {
        let mut off = 0;
        let len = cmp::min(src.len(), self.remaining());

        while off < len {
            let mut cnt;

            unsafe {
                let dst = self.mut_bytes();
                cnt = cmp::min(dst.len(), len - off);

                ptr::copy_nonoverlapping_memory(
                    dst.as_mut_ptr(), src[off..].as_ptr(), cnt);

                off += cnt;
            }

            self.advance(cnt);
        }

        len
    }

    /// Write a single byte to the `MuBuf`
    fn write_byte(&mut self, byte: u8) -> bool {
        let src = [byte];

        if self.write_slice(&src) == 0 {
            return false;
        }

        true
    }
}

/// An extension trait providing extra functions applicable to all `MutBuf` values.
pub trait MutBufExt {

    /// Write bytes from the given source into the current `MutBuf` and advance
    /// the cursor by the number of bytes written.
    fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error>;
}

/*
 *
 * ===== ByteStr =====
 *
 */

/// An immutable sequence of bytes. Operations will not mutate the original
/// value. Since only immutable access is permitted, operations do not require
/// copying (though, sometimes copying will happen as an optimization).
pub trait ByteStr : Clone + Sized + Send + Sync + ops::Index<usize, Output=u8> {

    // Until HKT lands, the buf must be bound by 'static
    type Buf: Buf+'static;

    /// Returns a read-only `Buf` for accessing the byte contents of the
    /// `ByteStr`.
    fn buf(&self) -> Self::Buf;

    /// Returns a new `Bytes` value representing the concatenation of `self`
    /// with the given `Bytes`.
    fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes;

    /// Returns the number of bytes in the ByteStr
    fn len(&self) -> usize;

    /// Returns true if the length of the `ByteStr` is 0
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a new ByteStr value containing the byte range between `begin`
    /// (inclusive) and `end` (exclusive)
    fn slice(&self, begin: usize, end: usize) -> Bytes;

    /// Returns a new ByteStr value containing the byte range starting from
    /// `begin` (inclusive) to the end of the byte str.
    ///
    /// Equivalent to `bytes.slice(begin, bytes.len())`
    fn slice_from(&self, begin: usize) -> Bytes {
        self.slice(begin, self.len())
    }

    /// Returns a new ByteStr value containing the byte range from the start up
    /// to `end` (exclusive).
    ///
    /// Equivalent to `bytes.slice(0, end)`
    fn slice_to(&self, end: usize) -> Bytes {
        self.slice(0, end)
    }

    /// Divides the value into two `Bytes` at the given index.
    ///
    /// The first will contain all bytes from `[0, mid]` (excluding the index
    /// `mid` itself) and the second will contain all indices from `[mid, len)`
    /// (excluding the index `len` itself).
    ///
    /// Panics if `mid > len`.
    fn split_at(&self, mid: usize) -> (Bytes, Bytes) {
        (self.slice_to(mid), self.slice_from(mid))
    }

    /// Consumes the value and returns a `Bytes` instance containing
    /// identical bytes
    fn to_bytes(self) -> Bytes;
}

/*
 *
 * ===== *Ext impls =====
 *
 */

impl<B: Buf> BufExt for B {
    fn read<S: Sink>(&mut self, dst: S) -> Result<usize, S::Error> {
        dst.sink(self)
    }
}

impl<B: MutBuf> MutBufExt for B {
    fn write<S: Source>(&mut self, src: S) -> Result<usize, S::Error> {
        src.fill(self)
    }
}

/*
 *
 * ===== Sink / Source =====
 *
 */

/// A value that reads bytes from a Buf into itself
pub trait Sink {
    type Error;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}

/// A value that writes bytes from itself into a `MutBuf`.
pub trait Source {
    type Error;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, Self::Error>;
}

impl<'a> Sink for &'a mut [u8] {
    type Error = BufError;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.read_slice(self))
    }
}

impl<'a> Sink for &'a mut Vec<u8> {
    type Error = BufError;

    fn sink<B: Buf>(self, buf: &mut B) -> Result<usize, BufError> {
        use std::slice;

        let rem = buf.remaining();
        let cap = self.capacity();
        let len = rem - cap;

        // Ensure that the vec is big enough
        if cap < rem {
            self.reserve(len);
        }

        unsafe {
            {
                let dst = self.as_mut_slice();
                buf.read_slice(slice::from_raw_parts_mut(dst.as_mut_ptr(), rem));
            }

            self.set_len(rem);
        }

        Ok(len)
    }
}

impl<'a> Source for &'a [u8] {
    type Error = BufError;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.write_slice(self))
    }
}

impl<'a> Source for &'a Vec<u8> {
    type Error = BufError;

    fn fill<B: MutBuf>(self, buf: &mut B) -> Result<usize, BufError> {
        Ok(buf.write_slice(self.as_slice()))
    }
}

impl<'a> Source for &'a Bytes {
    type Error = BufError;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
        unimplemented!();
    }
}

impl<'a> Source for &'a mut (io::Read+'a) {
    type Error = io::Error;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, io::Error> {
        unimplemented!();
    }
}

impl<'a> Source for &'a mut (Iterator<Item=u8>+'a) {
    type Error = BufError;

    fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> {
        unimplemented!();
    }
}

/*
 *
 * ===== Buf impls =====
 *
 */

impl Buf for Box<Buf+'static> {
    fn remaining(&self) -> usize {
        (**self).remaining()
    }

    fn bytes(&self) -> &[u8] {
        (**self).bytes()
    }

    fn advance(&mut self, cnt: usize) {
        (**self).advance(cnt);
    }

    fn read_slice(&mut self, dst: &mut [u8]) -> usize {
        (**self).read_slice(dst)
    }
}

/*
 *
 * ===== BufError  =====
 *
 */

#[derive(Copy, Debug)]
pub enum BufError {
    Underflow,
    Overflow,
}
<|endoftext|>


<commit_before>#![cfg_attr(feature="nightly", feature(plugin))]
#![cfg_attr(feature="nightly", plugin(clippy))]
#![cfg_attr(feature="nightly", deny(warnings))]

#[macro_use]
extern crate maplit;
extern crate env_logger;
extern crate uuid;
extern crate serde;
extern crate serde_json;
extern crate rustc_serialize;
extern crate handlebars;
#[macro_use]
extern crate log;
extern crate num;

#[macro_use]
mod macros;

pub use correlator::Correlator;
pub use config::action::ActionType;
pub use dispatcher::Response;
pub use message::Message;

pub mod conditions;
pub mod config;
pub mod action;
mod context;
pub mod correlator;
pub mod dispatcher;
pub mod message;
pub mod reactor;
mod state;
pub mod test_utils;
mod timer;
mod duration;
<commit_msg>lib: pub reexport ContextMap<commit_after>#![cfg_attr(feature="nightly", feature(plugin))]
#![cfg_attr(feature="nightly", plugin(clippy))]
#![cfg_attr(feature="nightly", deny(warnings))]

#[macro_use]
extern crate maplit;
extern crate env_logger;
extern crate uuid;
extern crate serde;
extern crate serde_json;
extern crate rustc_serialize;
extern crate handlebars;
#[macro_use]
extern crate log;
extern crate num;

#[macro_use]
mod macros;

pub use correlator::Correlator;
pub use config::action::ActionType;
pub use dispatcher::Response;
pub use message::Message;
pub use context::ContextMap;

pub mod conditions;
pub mod config;
pub mod action;
mod context;
pub mod correlator;
pub mod dispatcher;
pub mod message;
pub mod reactor;
mod state;
pub mod test_utils;
mod timer;
mod duration;
<|endoftext|>


<commit_before>extern crate libc;

use std::os::raw;
use std::ffi::CString;
use std::mem::{transmute, size_of};

#[link(name = "klee")]
extern {
  fn klee_make_symbolic(data: *const raw::c_void, length: libc::size_t, name: *const raw::c_char);
  fn klee_int(name: *const raw::c_char) -> raw::c_int;
}

pub unsafe fn any(data: *const raw::c_void, length: usize, name: &str) {
  let name_cstr = CString::new(name).unwrap();
  klee_make_symbolic(data, length as libc::size_t, name_cstr.as_ptr());
}

pub fn new_i32(name: &str) -> i32 {
  let result;
  let name_cstr = CString::new(name).unwrap();
  unsafe {
    result = klee_int(name_cstr.as_ptr());
  }
  result
}

pub fn i32(data: *const i32, name: &str) {
  unsafe { any(transmute(data), size_of::<i32>(), name); }
}

pub fn u32(data: *const u32, name: &str) {
  unsafe { any(transmute(data), size_of::<u32>(), name); }
}

pub fn i64(data: *const i64, name: &str) {
  unsafe { any(transmute(data), size_of::<i64>(), name); }
}

pub fn u64(data: *const u64, name: &str) {
  unsafe { any(transmute(data), size_of::<u64>(), name); }
}

pub fn str(data: &str, name: &str) {
  unsafe { any(transmute(data.as_ptr()), data.len(), name); }
}

pub fn bytes(data: &[u8], name: &str) {
  unsafe { any(transmute(data.as_ptr()), data.len(), name); }
}
<commit_msg>Update lib.rs<commit_after>extern crate libc;

use std::os::raw;
use std::ffi::CString;
use std::mem::{transmute, size_of};

#[link(name = "klee")]
extern {
  fn klee_make_symbolic(data: *const raw::c_void, length: libc::size_t, name: *const raw::c_char);
  fn klee_int(name: *const raw::c_char) -> raw::c_int;
}

pub unsafe fn any(data: *const raw::c_void, length: usize, name: &str) {
  let name_cstr = CString::new(name).unwrap();
  klee_make_symbolic(data, length as libc::size_t, name_cstr.as_ptr());
}

pub fn i32(name: &str) -> i32 {
  let result;
  let name_cstr = CString::new(name).unwrap();
  unsafe {
    result = klee_int(name_cstr.as_ptr());
  }
  result
}

pub fn make_sym<T>(data: &T, name: &str) {
  unsafe{ any(transmute(data as *const T), sizeof::<T>(), name); }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use std::str;

use nom::IResult;

pub struct Edo {

}

#[derive(Debug, PartialEq)]
enum Expression<'a> {
    Function(&'a str),
    Literal(&'a str),
}

// Parse a function
named!(function<&[u8], &str>, map_res!(
    delimited!(
        char!('{'),
        take_until!("}"),
        char!('}')
    ),
    str::from_utf8
));

// Parse multiple functions
named!(functions<&[u8], Vec<&str> >, many0!(function));

impl Edo {
    pub fn new() -> Edo {
        Edo {
        }
    }

    fn parse<'a>(self, input: &'a str) -> IResult<&[u8], Vec<Expression>> {
        let (_, parsed_functions) = try_parse!(input.as_bytes(), functions);
        let functions: Vec<Expression> = parsed_functions
            .iter()
            .map(|name| Expression::Function(name))
            .collect();
        IResult::Done(&b""[..], functions)
    }
}

#[cfg(test)]
mod tests {
    use nom::IResult;

    use super::{Edo, Expression, function, functions};

    #[test]
    fn parse_function() {
        assert_eq!(
            function(b"{test}"),
            IResult::Done(
                &b""[..],
                "test"
            )
        );
    }

    #[test]
    fn parse_multiple_functions() {
        assert_eq!(
            functions(b"{test}{haha}"),
            IResult::Done(
                &b""[..],
                vec!["test", "haha"]
            )
        );
    }
}
<commit_msg>DRY out parsing<commit_after>#[macro_use]
extern crate nom;

use std::str;

use nom::IResult;

pub struct Edo {

}

#[derive(Debug, PartialEq)]
enum Expression<'a> {
    Function(&'a str),
    Literal(&'a str),
}

// Parse a function
named!(function<&[u8], Expression>, map!(
    map_res!(
        delimited!(
            char!('{'),
            take_until!("}"),
            char!('}')
        ),
        str::from_utf8
    ),
    Expression::Function
));

// Parse a literal
named!(literal<&[u8], Expression>, map!(
    map_res!(
        is_not!("{"),
        str::from_utf8
    ),
    Expression::Literal
));

// Parse multiple functions and text literals
named!(expressions<&[u8], Vec<Expression> >, many0!(alt!(
    function |
    literal
)));

impl Edo {
    pub fn new() -> Edo {
        Edo {
        }
    }

    fn parse<'a>(self, input: &'a str) -> IResult<&[u8], Vec<Expression>> {
        let (_, parsed_expressions) = try_parse!(
            input.as_bytes(),
            expressions
        );
        IResult::Done(&b""[..], parsed_expressions)
    }
}

#[cfg(test)]
mod tests {
    use nom::IResult;

    use super::{Edo, Expression, function, literal, expressions};

    #[test]
    fn parse_function() {
        assert_eq!(
            function(b"{test}"),
            IResult::Done(
                &b""[..],
                Expression::Function("test")
            )
        );
    }

    #[test]
    fn parse_literal() {
        assert_eq!(
            literal(b"testing"),
            IResult::Done(
                &b""[..],
                Expression::Literal("testing")
            )
        );
    }

    #[test]
    fn parse_multiple_expressions() {
        assert_eq!(
            expressions(b"{test}literal{test2}haha"),
            IResult::Done(
                &b""[..],
                vec![
                    Expression::Function("test"),
                    Expression::Literal("literal"),
                    Expression::Function("test2"),
                    Expression::Literal("haha"),
                ]
            )
        );

        assert_eq!(
            expressions(b"haha{test}"),
            IResult::Done(
                &b""[..],
                vec![
                    Expression::Literal("haha"),
                    Expression::Function("test"),
                ]
            )
        );
    }

    #[test]
    fn parse_method() {
        let edo = Edo::new();
        assert_eq!(
            edo.parse("haha{test}"),
            IResult::Done(
                &b""[..],
                vec![
                    Expression::Literal("haha"),
                    Expression::Function("test"),
                ]
            )
        );
    }
}
<|endoftext|>