<commit_before>use core::marker::PhantomData;

/// This Tag provides an initial host memory map.
///
/// The map provided is guaranteed to list all standard RAM that should be
/// available for normal use. This type however includes the regions occupied
/// by kernel, mbi, segments and modules. Kernel must take care not to
/// overwrite these regions.
///
/// This tag may not be provided by some boot loaders on EFI platforms if EFI
/// boot services are enabled and available for the loaded image (The EFI boot
/// services tag may exist in the Multiboot2 boot information structure).
#[derive(Debug)]
#[repr(C)]
pub struct MemoryMapTag {
    typ: u32,
    size: u32,
    entry_size: u32,
    entry_version: u32,
    first_area: MemoryArea,
}

impl MemoryMapTag {
    /// Return an iterator over all AVAILABLE marked memory areas.
    pub fn memory_areas(&self) -> MemoryAreaIter {
        MemoryAreaIter {
            iter: self.all_memory_areas();
        }
    }
    /// Return an iterator over all marked memory areas.
    pub fn all_memory_areas(&self) -> AllMemoryAreaIter {
        let self_ptr = self as *const MemoryMapTag;
        let start_area = (&self.first_area) as *const MemoryArea;
        AllMemoryAreaIter {
            current_area: start_area as u64,
            last_area: (self_ptr as u64 + (self.size - self.entry_size) as u64),
            entry_size: self.entry_size,
            phantom: PhantomData,
        }
    }
}

/// A memory area entry descriptor.
#[derive(Debug)]
#[repr(C)]
pub struct MemoryArea {
    base_addr: u64,
    length: u64,
    typ: u32,
    _reserved: u32,
}

impl MemoryArea {
    /// The start address of the memory region.
    pub fn start_address(&self) -> u64 {
        self.base_addr
    }

    /// The end address of the memory region.
    pub fn end_address(&self) -> u64 {
        self.base_addr + self.length
    }

    /// The size, in bytes, of the memory region.
    pub fn size(&self) -> u64 {
        self.length
    }

    /// The type of the memory region.
    pub fn typ(&self) -> MemoryAreaType {
        match self.typ {
            1 => MemoryAreaType::Available,
            3 => MemoryAreaType::AcpiAvailable,
            4 => MemoryAreaType::ReservedHibernate,
            5 => MemoryAreaType::Defective,
            _ => MemoryAreaType::Reserved,
        }
    }
}

/// An enum of possible reported region types.
#[derive(Debug, PartialEq, Eq)]
pub enum MemoryAreaType {
    /// A reserved area that must not be used.
    Reserved,

    /// Available memory free to be used by the OS.
    Available,

    /// Usable memory holding ACPI information.
    AcpiAvailable,

    /// Reserved memory which needs to be preserved on hibernation.
    ReservedHibernate,

    /// Memory which is occupied by defective RAM modules.
    Defective,
}

/// An iterator over all memory areas
#[derive(Clone, Debug)]
pub struct AllMemoryAreaIter<'a> {
    current_area: u64,
    last_area: u64,
    entry_size: u32,
    phantom: PhantomData<&'a MemoryArea>,
}

impl<'a> Iterator for AllMemoryAreaIter<'a> {
    type Item = &'a MemoryArea;
    fn next(&mut self) -> Option<&'a MemoryArea> {
        if self.current_area > self.last_area {
            None
        } else {
            let area = unsafe{&*(self.current_area as *const MemoryArea)};
            self.current_area = self.current_area + (self.entry_size as u64);
            Some(area)
        }
    }
}

/// An iterator over Available memory areas.
#[derive(Clone, Debug)]
pub struct MemoryAreaIter<'a> {
    iter: AllMemoryAreaIter<'a>,
}

impl<'a> Iterator for MemoryAreaIter<'a> {
    type Item = &'a MemoryArea;
    fn next(&mut self) -> Option<&'a MemoryArea> {
        let ret = self.iter.next()?;
        if ret.typ == 1 {
            Some(ret)
        } else {
            self.next()
        }
    }
}

/// EFI memory map as per EFI specification.
#[derive(Debug)]
#[repr(C)]
pub struct EFIMemoryMapTag {
    typ: u32,
    size: u32,
    desc_size: u32,
    desc_version: u32,
    first_desc: EFIMemoryDesc,
}

impl EFIMemoryMapTag {
    /// Return an iterator over ALL marked memory areas.
    ///
    /// This differs from `MemoryMapTag` as for UEFI, the OS needs some non-
    /// available memory areas for tables and such.
    pub fn memory_areas(&self) -> EFIMemoryAreaIter {
        let self_ptr = self as *const EFIMemoryMapTag;
        let start_area = (&self.first_desc) as *const EFIMemoryDesc;
        EFIMemoryAreaIter {
            current_area: start_area as u64,
            last_area: (self_ptr as u64 + self.size as u64),
            entry_size: self.desc_size,
            phantom: PhantomData,
        }
    }
}

/// EFI Boot Memory Map Descriptor
#[derive(Debug)]
#[repr(C)]
pub struct EFIMemoryDesc {
    typ: u32,
    _padding: u32,
    phys_addr: u64,
    virt_addr: u64,
    num_pages: u64,
    attr: u64,
}

/// An enum of possible reported region types.
#[derive(Debug, PartialEq, Eq)]
pub enum EFIMemoryAreaType {
    /// Unusable.
    EfiReservedMemoryType,
    /// Code area of a UEFI application.
    EfiLoaderCode,
    /// Data area of a UEFI application.
    EfiLoaderData,
    /// Code area of a UEFI Boot Service Driver.
    EfiBootServicesCode,
    /// Data area of a UEFI Boot Service Driver.
    EfiBootServicesData,
    /// Code area of a UEFI Runtime Driver.
    ///
    /// Must be preserved in working and ACPI S1-S3 states.
    EfiRuntimeServicesCode,
    /// Data area of a UEFI Runtime Driver.
    ///
    /// Must be preserved in working and ACPI S1-S3 states.
    EfiRuntimeServicesData,
    /// Available memory.
    EfiConventionalMemory,
    /// Memory with errors, treat as unusable.
    EfiUnusableMemory,
    /// Memory containing the ACPI tables.
    ///
    /// Must be preserved in working and ACPI S1-S3 states.
    EfiACPIReclaimMemory,
    /// Memory reserved by firmware.
    ///
    /// Must be preserved in working and ACPI S1-S3 states.
    EfiACPIMemoryNVS,
    /// Memory used by firmware for requesting memory mapping of IO.
    ///
    /// Should not be used by the OS. Use the ACPI tables for memory mapped IO
    /// information.
    EfiMemoryMappedIO,
    /// Memory used to translate memory cycles to IO cycles.
    ///
    /// Should not be used by the OS. Use the ACPI tables for memory mapped IO
    /// information.
    EfiMemoryMappedIOPortSpace,
    /// Memory used by the processor.
    ///
    /// Must be preserved in working and ACPI S1-S4 states. Processor defined
    /// otherwise.
    EfiPalCode,
    /// Available memory supporting byte-addressable non-volatility.
    EfiPersistentMemory,
    /// Unknown region type, treat as unusable.
    EfiUnknown,
}

impl EFIMemoryDesc {
    /// The physical address of the memory region.
    pub fn physical_address(&self) -> u64 {
        self.phys_addr
    }

    /// The virtual address of the memory region.
    pub fn virtual_address(&self) -> u64 {
        self.virt_addr
    }

    /// The size in bytes of the memory region.
    pub fn size(&self) -> u64 {
        // Spec says this is number of 4KiB pages.
        self.num_pages * 4096
    }

    /// The type of the memory region.
    pub fn typ(&self) -> EFIMemoryAreaType {
        match self.typ {
            0 => EFIMemoryAreaType::EfiReservedMemoryType,
            1 => EFIMemoryAreaType::EfiLoaderCode,
            2 => EFIMemoryAreaType::EfiLoaderData,
            3 => EFIMemoryAreaType::EfiBootServicesCode,
            4 => EFIMemoryAreaType::EfiBootServicesData,
            5 => EFIMemoryAreaType::EfiRuntimeServicesCode,
            6 => EFIMemoryAreaType::EfiRuntimeServicesData,
            7 => EFIMemoryAreaType::EfiConventionalMemory,
            8 => EFIMemoryAreaType::EfiUnusableMemory,
            9 => EFIMemoryAreaType::EfiACPIReclaimMemory,
            10 => EFIMemoryAreaType::EfiACPIMemoryNVS,
            11 => EFIMemoryAreaType::EfiMemoryMappedIO,
            12 => EFIMemoryAreaType::EfiMemoryMappedIOPortSpace,
            13 => EFIMemoryAreaType::EfiPalCode,
            14 => EFIMemoryAreaType::EfiPersistentMemory,
            _ => EFIMemoryAreaType::EfiUnknown,
        }
    }
}

/// EFI ExitBootServices was not called
#[derive(Debug)]
#[repr(C)]
pub struct EFIBootServicesNotExited {
    typ: u32,
    size: u32,
}

/// An iterator over ALL EFI memory areas.
#[derive(Clone, Debug)]
pub struct EFIMemoryAreaIter<'a> {
    current_area: u64,
    last_area: u64,
    entry_size: u32,
    phantom: PhantomData<&'a EFIMemoryDesc>,
}

impl<'a> Iterator for EFIMemoryAreaIter<'a> {
    type Item = &'a EFIMemoryDesc;
    fn next(&mut self) -> Option<&'a EFIMemoryDesc> {
        if self.current_area > self.last_area {
            None
        } else {
            let area = unsafe{&*(self.current_area as *const EFIMemoryDesc)};
            self.current_area = self.current_area + (self.entry_size as u64);
            Some(area)
        }
    }
}

<commit_msg>Fix Syntax Error<commit_after>use core::marker::PhantomData;

/// This Tag provides an initial host memory map.
///
/// The map provided is guaranteed to list all standard RAM that should be
/// available for normal use. This type however includes the regions occupied
/// by kernel, mbi, segments and modules. Kernel must take care not to
/// overwrite these regions.
///
/// This tag may not be provided by some boot loaders on EFI platforms if EFI
/// boot services are enabled and available for the loaded image (The EFI boot
/// services tag may exist in the Multiboot2 boot information structure).
#[derive(Debug)]
#[repr(C)]
pub struct MemoryMapTag {
    typ: u32,
    size: u32,
    entry_size: u32,
    entry_version: u32,
    first_area: MemoryArea,
}

impl MemoryMapTag {
    /// Return an iterator over all AVAILABLE marked memory areas.
    pub fn memory_areas(&self) -> MemoryAreaIter {
        MemoryAreaIter {
            iter: self.all_memory_areas(),
        }
    }
    /// Return an iterator over all marked memory areas.
    pub fn all_memory_areas(&self) -> AllMemoryAreaIter {
        let self_ptr = self as *const MemoryMapTag;
        let start_area = (&self.first_area) as *const MemoryArea;
        AllMemoryAreaIter {
            current_area: start_area as u64,
            last_area: (self_ptr as u64 + (self.size - self.entry_size) as u64),
            entry_size: self.entry_size,
            phantom: PhantomData,
        }
    }
}

/// A memory area entry descriptor.
#[derive(Debug)]
#[repr(C)]
pub struct MemoryArea {
    base_addr: u64,
    length: u64,
    typ: u32,
    _reserved: u32,
}

impl MemoryArea {
    /// The start address of the memory region.
    pub fn start_address(&self) -> u64 {
        self.base_addr
    }

    /// The end address of the memory region.
    pub fn end_address(&self) -> u64 {
        self.base_addr + self.length
    }

    /// The size, in bytes, of the memory region.
    pub fn size(&self) -> u64 {
        self.length
    }

    /// The type of the memory region.
    pub fn typ(&self) -> MemoryAreaType {
        match self.typ {
            1 => MemoryAreaType::Available,
            3 => MemoryAreaType::AcpiAvailable,
            4 => MemoryAreaType::ReservedHibernate,
            5 => MemoryAreaType::Defective,
            _ => MemoryAreaType::Reserved,
        }
    }
}

/// An enum of possible reported region types.
#[derive(Debug, PartialEq, Eq)]
pub enum MemoryAreaType {
    /// A reserved area that must not be used.
    Reserved,

    /// Available memory free to be used by the OS.
    Available,

    /// Usable memory holding ACPI information.
    AcpiAvailable,

    /// Reserved memory which needs to be preserved on hibernation.
    ReservedHibernate,

    /// Memory which is occupied by defective RAM modules.
    Defective,
}

/// An iterator over all memory areas
#[derive(Clone, Debug)]
pub struct AllMemoryAreaIter<'a> {
    current_area: u64,
    last_area: u64,
    entry_size: u32,
    phantom: PhantomData<&'a MemoryArea>,
}

impl<'a> Iterator for AllMemoryAreaIter<'a> {
    type Item = &'a MemoryArea;
    fn next(&mut self) -> Option<&'a MemoryArea> {
        if self.current_area > self.last_area {
            None
        } else {
            let area = unsafe{&*(self.current_area as *const MemoryArea)};
            self.current_area = self.current_area + (self.entry_size as u64);
            Some(area)
        }
    }
}

/// An iterator over Available memory areas.
#[derive(Clone, Debug)]
pub struct MemoryAreaIter<'a> {
    iter: AllMemoryAreaIter<'a>,
}

impl<'a> Iterator for MemoryAreaIter<'a> {
    type Item = &'a MemoryArea;
    fn next(&mut self) -> Option<&'a MemoryArea> {
        let ret = self.iter.next()?;
        if ret.typ == 1 {
            Some(ret)
        } else {
            self.next()
        }
    }
}

/// EFI memory map as per EFI specification.
#[derive(Debug)]
#[repr(C)]
pub struct EFIMemoryMapTag {
    typ: u32,
    size: u32,
    desc_size: u32,
    desc_version: u32,
    first_desc: EFIMemoryDesc,
}

impl EFIMemoryMapTag {
    /// Return an iterator over ALL marked memory areas.
    ///
    /// This differs from `MemoryMapTag` as for UEFI, the OS needs some non-
    /// available memory areas for tables and such.
    pub fn memory_areas(&self) -> EFIMemoryAreaIter {
        let self_ptr = self as *const EFIMemoryMapTag;
        let start_area = (&self.first_desc) as *const EFIMemoryDesc;
        EFIMemoryAreaIter {
            current_area: start_area as u64,
            last_area: (self_ptr as u64 + self.size as u64),
            entry_size: self.desc_size,
            phantom: PhantomData,
        }
    }
}

/// EFI Boot Memory Map Descriptor
#[derive(Debug)]
#[repr(C)]
pub struct EFIMemoryDesc {
    typ: u32,
    _padding: u32,
    phys_addr: u64,
    virt_addr: u64,
    num_pages: u64,
    attr: u64,
}

/// An enum of possible reported region types.
#[derive(Debug, PartialEq, Eq)]
pub enum EFIMemoryAreaType {
    /// Unusable.
    EfiReservedMemoryType,
    /// Code area of a UEFI application.
    EfiLoaderCode,
    /// Data area of a UEFI application.
    EfiLoaderData,
    /// Code area of a UEFI Boot Service Driver.
    EfiBootServicesCode,
    /// Data area of a UEFI Boot Service Driver.
    EfiBootServicesData,
    /// Code area of a UEFI Runtime Driver.
    ///
    /// Must be preserved in working and ACPI S1-S3 states.
    EfiRuntimeServicesCode,
    /// Data area of a UEFI Runtime Driver.
    ///
    /// Must be preserved in working and ACPI S1-S3 states.
    EfiRuntimeServicesData,
    /// Available memory.
    EfiConventionalMemory,
    /// Memory with errors, treat as unusable.
    EfiUnusableMemory,
    /// Memory containing the ACPI tables.
    ///
    /// Must be preserved in working and ACPI S1-S3 states.
    EfiACPIReclaimMemory,
    /// Memory reserved by firmware.
    ///
    /// Must be preserved in working and ACPI S1-S3 states.
    EfiACPIMemoryNVS,
    /// Memory used by firmware for requesting memory mapping of IO.
    ///
    /// Should not be used by the OS. Use the ACPI tables for memory mapped IO
    /// information.
    EfiMemoryMappedIO,
    /// Memory used to translate memory cycles to IO cycles.
    ///
    /// Should not be used by the OS. Use the ACPI tables for memory mapped IO
    /// information.
    EfiMemoryMappedIOPortSpace,
    /// Memory used by the processor.
    ///
    /// Must be preserved in working and ACPI S1-S4 states. Processor defined
    /// otherwise.
    EfiPalCode,
    /// Available memory supporting byte-addressable non-volatility.
    EfiPersistentMemory,
    /// Unknown region type, treat as unusable.
    EfiUnknown,
}

impl EFIMemoryDesc {
    /// The physical address of the memory region.
    pub fn physical_address(&self) -> u64 {
        self.phys_addr
    }

    /// The virtual address of the memory region.
    pub fn virtual_address(&self) -> u64 {
        self.virt_addr
    }

    /// The size in bytes of the memory region.
    pub fn size(&self) -> u64 {
        // Spec says this is number of 4KiB pages.
        self.num_pages * 4096
    }

    /// The type of the memory region.
    pub fn typ(&self) -> EFIMemoryAreaType {
        match self.typ {
            0 => EFIMemoryAreaType::EfiReservedMemoryType,
            1 => EFIMemoryAreaType::EfiLoaderCode,
            2 => EFIMemoryAreaType::EfiLoaderData,
            3 => EFIMemoryAreaType::EfiBootServicesCode,
            4 => EFIMemoryAreaType::EfiBootServicesData,
            5 => EFIMemoryAreaType::EfiRuntimeServicesCode,
            6 => EFIMemoryAreaType::EfiRuntimeServicesData,
            7 => EFIMemoryAreaType::EfiConventionalMemory,
            8 => EFIMemoryAreaType::EfiUnusableMemory,
            9 => EFIMemoryAreaType::EfiACPIReclaimMemory,
            10 => EFIMemoryAreaType::EfiACPIMemoryNVS,
            11 => EFIMemoryAreaType::EfiMemoryMappedIO,
            12 => EFIMemoryAreaType::EfiMemoryMappedIOPortSpace,
            13 => EFIMemoryAreaType::EfiPalCode,
            14 => EFIMemoryAreaType::EfiPersistentMemory,
            _ => EFIMemoryAreaType::EfiUnknown,
        }
    }
}

/// EFI ExitBootServices was not called
#[derive(Debug)]
#[repr(C)]
pub struct EFIBootServicesNotExited {
    typ: u32,
    size: u32,
}

/// An iterator over ALL EFI memory areas.
#[derive(Clone, Debug)]
pub struct EFIMemoryAreaIter<'a> {
    current_area: u64,
    last_area: u64,
    entry_size: u32,
    phantom: PhantomData<&'a EFIMemoryDesc>,
}

impl<'a> Iterator for EFIMemoryAreaIter<'a> {
    type Item = &'a EFIMemoryDesc;
    fn next(&mut self) -> Option<&'a EFIMemoryDesc> {
        if self.current_area > self.last_area {
            None
        } else {
            let area = unsafe{&*(self.current_area as *const EFIMemoryDesc)};
            self.current_area = self.current_area + (self.entry_size as u64);
            Some(area)
        }
    }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
#[macro_use]
extern crate json;
extern crate curl;
extern crate getopts;
extern crate mktemp;
extern crate mpmc;
extern crate regex;
extern crate shuteye;
extern crate tic;
extern crate tiny_http;
extern crate toml;
extern crate sha_1;
extern crate hmac;
extern crate rustc_serialize;

mod common;
mod consumer;
mod webhook;
mod publisher;

use common::logging::set_log_level;
use consumer::cargo;
use getopts::Options;
use std::{env, process};

pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub const PROGRAM: &'static str = env!("CARGO_PKG_NAME");

fn print_usage(program: &str, opts: &Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn opts() -> Options {
    let mut opts = Options::new();

    // general
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("", "version", "show version and exit");
    opts.optflagmulti("v", "verbose", "verbosity (stacking)");

    // clippy
    opts.optflag("", "no-clippy", "skip clippy");

    // fuzzing
    opts.optflag("", "no-fuzz", "skip fuzzing");
    opts.optopt("d", "fuzz-duration", "time per fuzz target", "[SECONDS]");
    opts.optopt(
        "c",
        "fuzz-cores",
        "number of cores to use during fuzzing",
        "[CORES]",
    );

    // cross targets
    opts.optflag("", "no-cross", "skip cross targets");

    opts
}

pub fn init() -> getopts::Matches {
    let args: Vec<String> = env::args().collect();
    let program = &args[0];
    let opts = opts();

    let options = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            println!("Failed to parse command line args: {}", f);
            process::exit(1);
        }
    };

    if options.opt_present("help") {
        print_usage(program, &opts);
        process::exit(0);
    }

    if options.opt_present("version") {
        println!("{} {}", PROGRAM, VERSION);
        process::exit(0);
    }

    options
}

fn main() {
    let options = init();

    // initialize logging
    set_log_level(options.opt_count("verbose"));
    info!("{} {}", PROGRAM, VERSION);

    let fuzz_duration: usize = options
        .opt_str("fuzz-duration")
        .unwrap_or("10".to_owned())
        .parse()
        .expect("--fuzz-duration invalid");

    let fuzz_cores: usize = options
        .opt_str("fuzz-cores")
        .unwrap_or("1".to_owned())
        .parse()
        .expect("--fuzz-duration invalid");

    // complete set of tests - native target
    let mut cargo = cargo::Cargo::new(".".to_owned());
    cargo.build().expect("cargo build: failed");
    cargo.test().expect("cargo test: failed");
    cargo.fmt().expect("cargo fmt: failed");
    if !options.opt_present("no-clippy") {
        cargo.clippy().expect("cargo clippy: failed");
    }
    if !options.opt_present("no-fuzz") {
        cargo.fuzz_all(fuzz_duration, fuzz_cores).expect(
            "cargo fuzz: failed",
        );
    }
    cargo.set_release(true);
    cargo.build().expect("cargo build --release: failed");
    cargo.test().expect("cargo test --release: failed");

    if !options.opt_present("no-cross") {
        let targets = vec![
            "aarch64-unknown-linux-gnu", // Tier-2
            "arm-unknown-linux-gnueabi", // Tier-2
            "arm-unknown-linux-gnueabihf", // Tier-2
            "armv7-unknown-linux-gnueabihf", // Tier-2
            "i686-unknown-linux-gnu", // Tier-1
            "i686-unknown-linux-musl", // Tier-2
            "x86_64-unknown-linux-gnu", // Tier-1
            "x86_64-unknown-linux-musl", // Tier-2
        ];

        // cross target tests
        for target in targets {
            info!("target: {}", target);
            let mut cargo = cargo::Cargo::new(".".to_owned());
            cargo.set_target(target.to_owned());
            cargo.build().expect("cargo build: failed");
            cargo.test().expect("cargo test: failed");
            cargo.set_release(true);
            cargo.build().expect("cargo build --release: failed");
            cargo.test().expect("cargo test --release: failed");
        }
    }
}
<commit_msg>feature: config file (#37)<commit_after>#[macro_use]
extern crate log;
#[macro_use]
extern crate json;
extern crate curl;
extern crate getopts;
extern crate mktemp;
extern crate mpmc;
extern crate regex;
extern crate shuteye;
extern crate tic;
extern crate tiny_http;
extern crate toml;
extern crate sha_1;
extern crate hmac;
extern crate rustc_serialize;

mod common;
mod consumer;
mod webhook;
mod publisher;

use common::logging::set_log_level;
use consumer::cargo;
use getopts::Matches;
use getopts::Options;
use std::{env, process};
use std::collections::BTreeMap;
use std::default::Default;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use toml::{Parser, Value};
use toml::Value::Table;

pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub const PROGRAM: &'static str = env!("CARGO_PKG_NAME");

fn print_usage(program: &str, opts: &Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn opts() -> Options {
    let mut opts = Options::new();

    // general
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("", "version", "show version and exit");
    opts.optflagmulti("v", "verbose", "verbosity (stacking)");

    // clippy
    opts.optflag("", "no-clippy", "skip clippy");

    // fuzzing
    opts.optflag("", "no-fuzz", "skip fuzzing");
    opts.optopt("d", "fuzz-duration", "time per fuzz target", "[SECONDS]");
    opts.optopt(
        "c",
        "fuzz-cores",
        "number of cores to use during fuzzing",
        "[CORES]",
    );

    // cross targets
    opts.optflag("", "no-cross", "skip cross targets");

    opts
}

pub fn init() -> getopts::Matches {
    let args: Vec<String> = env::args().collect();
    let program = &args[0];
    let opts = opts();

    let options = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            println!("Failed to parse command line args: {}", f);
            process::exit(1);
        }
    };

    if options.opt_present("help") {
        print_usage(program, &opts);
        process::exit(0);
    }

    if options.opt_present("version") {
        println!("{} {}", PROGRAM, VERSION);
        process::exit(0);
    }

    options
}

pub struct Config {
    fuzz: bool,
    fuzz_cores: usize,
    fuzz_seconds: usize,
    cross: bool,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            fuzz: true,
            fuzz_cores: 1,
            fuzz_seconds: 10,
            cross: true,
        }
    }
}

impl Config {
    pub fn set_fuzz_cores(&mut self, cores: usize) -> &mut Self {
        self.fuzz_cores = cores;
        self
    }

    pub fn fuzz_cores(&self) -> usize {
        self.fuzz_cores
    }

    pub fn set_fuzz_seconds(&mut self, seconds: usize) -> &mut Self {
        self.fuzz_seconds = seconds;
        self
    }

    pub fn fuzz_seconds(&self) -> usize {
        self.fuzz_seconds
    }

    pub fn set_fuzz(&mut self, enable: bool) -> &mut Self {
        self.fuzz = enable;
        self
    }

    pub fn fuzz(&self) -> bool {
        self.fuzz
    }

    pub fn set_cross(&mut self, enable: bool) -> &mut Self {
        self.cross = enable;
        self
    }

    pub fn cross(&self) -> bool {
        self.cross
    }
}

pub fn load_config(path: &Path, matches: &Matches) -> Result<Config, String> {
    let cfg_txt = match File::open(path) {
        Ok(mut f) => {
            let mut cfg_txt = String::new();
            f.read_to_string(&mut cfg_txt).unwrap();
            cfg_txt
        }
        Err(e) => return Err(format!("Error opening config: {}", e)),
    };

    let mut p = Parser::new(&cfg_txt);

    match p.parse() {
        Some(table) => {
            debug!("toml parsed successfully. creating config");
            load_config_table(&table)
        }

        None => {
            for err in &p.errors {
                let (loline, locol) = p.to_linecol(err.lo);
                let (hiline, hicol) = p.to_linecol(err.hi);
                println!(
                    "{:?}:{}:{}-{}:{} error: {}",
                    path,
                    loline,
                    locol,
                    hiline,
                    hicol,
                    err.desc
                );
            }
            Err("failed to load config".to_owned())
        }
    }
}

fn load_config_table(table: &BTreeMap<String, Value>) -> Result<Config, String> {

    let mut config = Config::default();

    if let Some(&Table(ref general)) = table.get("fuzz") {
        if let Some(v) = general.get("enable").and_then(|k| k.as_bool()) {
            config.set_fuzz(v as bool);
        }
    }

    if let Some(&Table(ref general)) = table.get("fuzz") {
        if let Some(v) = general.get("cores").and_then(|k| k.as_integer()) {
            config.set_fuzz_cores(v as usize);
        }
    }

    if let Some(&Table(ref general)) = table.get("fuzz") {
        if let Some(v) = general.get("seconds").and_then(|k| k.as_integer()) {
            config.set_fuzz_seconds(v as usize);
        }
    }

    if let Some(&Table(ref general)) = table.get("cross") {
        if let Some(v) = general.get("enable").and_then(|k| k.as_bool()) {
            config.set_cross(v as bool);
        }
    }

    Ok(config)
}

fn main() {
    let options = init();

    // initialize logging
    set_log_level(options.opt_count("verbose"));
    info!("{} {}", PROGRAM, VERSION);

    let config = load_config(Path::new(".crucible.toml"), &options).unwrap_or(Config::default());

    // complete set of tests - native target
    let mut cargo = cargo::Cargo::new(".".to_owned());
    cargo.build().expect("cargo build: failed");
    cargo.test().expect("cargo test: failed");
    cargo.fmt().expect("cargo fmt: failed");
    if !options.opt_present("no-clippy") {
        cargo.clippy().expect("cargo clippy: failed");
    }
    if !options.opt_present("no-fuzz") {
        cargo
            .fuzz_all(config.fuzz_seconds(), config.fuzz_cores())
            .expect("cargo fuzz: failed");
    }
    cargo.set_release(true);
    cargo.build().expect("cargo build --release: failed");
    cargo.test().expect("cargo test --release: failed");

    if !options.opt_present("no-cross") && config.cross() {
        let targets = vec![
            "aarch64-unknown-linux-gnu", // Tier-2
            "arm-unknown-linux-gnueabi", // Tier-2
            "arm-unknown-linux-gnueabihf", // Tier-2
            "armv7-unknown-linux-gnueabihf", // Tier-2
            "i686-unknown-linux-gnu", // Tier-1
            "i686-unknown-linux-musl", // Tier-2
            "x86_64-unknown-linux-gnu", // Tier-1
            "x86_64-unknown-linux-musl", // Tier-2
        ];

        // cross target tests
        for target in targets {
            info!("target: {}", target);
            let mut cargo = cargo::Cargo::new(".".to_owned());
            cargo.set_target(target.to_owned());
            cargo.build().expect("cargo build: failed");
            cargo.test().expect("cargo test: failed");
            cargo.set_release(true);
            cargo.build().expect("cargo build --release: failed");
            cargo.test().expect("cargo test --release: failed");
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2001-2010 Georges Menie (www.menie.org)
// Copyright 2010 Salvatore Sanfilippo (adapted to Redis coding style)
// Copyright 2017 Tyler Neely (ported to rust)
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the University of California, Berkeley nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

// CRC16 implementation according to CCITT standards.
//
// Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the
// following parameters:
//
// Name                       : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN"
// Width                      : 16 bit
// Poly                       : 1021 (That is actually x^16 + x^12 + x^5 + 1)
// Initialization             : 0000
// Reflect Input byte         : False
// Reflect Output CRC         : False
// Xor constant to output CRC : 0000
// Output for "123456789"     : 31C3
//

#[rustfmt_skip]
const CRC16TAB: [u16; 256] =
    [0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a,
     0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294,
     0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462,
     0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509,
     0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695,
     0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5,
     0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948,
     0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
     0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4,
     0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b,
     0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f,
     0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
     0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046,
     0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290,
     0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e,
     0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
     0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691,
     0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
     0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d,
     0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16,
     0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8,
     0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e,
     0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93,
     0x3eb2, 0x0ed1, 0x1ef0];

#[inline(always)]
pub fn crc16(buf: &[u8]) -> u16 {
    let mut crc = 0u16;
    for &b in &*buf {
        let idx = ((crc >> 8) ^ b as u16) & 0x00FF;
        let lookup = CRC16TAB[idx as usize];
        crc = (crc << 8) ^ lookup;
    }
    crc
}

#[inline(always)]
pub fn crc16_arr(buf: &[u8]) -> [u8; 2] {
    let crc16 = crc16(buf);
    [(crc16 >> 8) as u8, crc16 as u8]
}

#[test]
fn test_crc16() {
    let input_str = "123456789";
    assert_eq!(crc16(input_str.as_bytes()), 0x31c3);
}
<commit_msg>fix rustfmt attr<commit_after>// Copyright 2001-2010 Georges Menie (www.menie.org)
// Copyright 2010 Salvatore Sanfilippo (adapted to Redis coding style)
// Copyright 2017 Tyler Neely (ported to rust)
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the University of California, Berkeley nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

// CRC16 implementation according to CCITT standards.
//
// Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the
// following parameters:
//
// Name                       : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN"
// Width                      : 16 bit
// Poly                       : 1021 (That is actually x^16 + x^12 + x^5 + 1)
// Initialization             : 0000
// Reflect Input byte         : False
// Reflect Output CRC         : False
// Xor constant to output CRC : 0000
// Output for "123456789"     : 31C3
//

#[cfg_attr(rustfmt, rustfmt_skip)]
const CRC16TAB: [u16; 256] =
    [0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a,
     0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294,
     0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462,
     0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509,
     0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695,
     0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5,
     0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948,
     0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
     0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4,
     0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b,
     0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f,
     0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
     0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046,
     0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290,
     0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e,
     0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
     0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691,
     0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
     0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d,
     0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16,
     0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8,
     0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e,
     0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93,
     0x3eb2, 0x0ed1, 0x1ef0];

#[inline(always)]
pub fn crc16(buf: &[u8]) -> u16 {
    let mut crc = 0u16;
    for &b in &*buf {
        let idx = ((crc >> 8) ^ b as u16) & 0x00FF;
        let lookup = CRC16TAB[idx as usize];
        crc = (crc << 8) ^ lookup;
    }
    crc
}

#[inline(always)]
pub fn crc16_arr(buf: &[u8]) -> [u8; 2] {
    let crc16 = crc16(buf);
    [(crc16 >> 8) as u8, crc16 as u8]
}

#[test]
fn test_crc16() {
    let input_str = "123456789";
    assert_eq!(crc16(input_str.as_bytes()), 0x31c3);
}
<|endoftext|>


<commit_before>//! # Drains
//!
//! Drains are responsible for filtering, formatting and writing the log records
//! into given destination.
use super::{Level};
use super::format;
use super::logger::RecordInfo;
use std::{io, str};
use std::sync::Mutex;
use super::{OwnedKeyValue,BorrowedKeyValue};
use std::sync::mpsc;
use std::thread;

///
/// Drain for Loggers
///
/// Implementing this trait allows writing own Drains
pub trait Drain : Send+Sync {
    /// Write one logging record
    fn log(&self, info : &RecordInfo, &[OwnedKeyValue], &[BorrowedKeyValue]);
}

/// Drain formating records and writing them to a byte-stream (io::Write)
///
/// Uses mutex to serialize writes.
/// TODO: Add one that does not serialize?
pub struct Streamer<W : io::Write, F : format::Format> {
    io : Mutex<W>,
    format : F,
}

impl<W : io::Write, F : format::Format> Streamer<W, F> {
    /// Create new `Streamer` writing to `io` using `format`
    pub fn new(io : W, format : F) -> Self {
        Streamer {
            io: Mutex::new(io),
            format : format,
        }
    }
}

impl<W : 'static+io::Write+Send, F : format::Format+Send> Drain for Streamer<W, F> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        let formatted = self.format.format(info, logger_values, values);

        let mut io = self.io.lock().unwrap();
        let _ = write!(io, "{}", formatted);
    }
}

/// Record log level filter
///
/// Wraps a drain and passes records to it, only
/// if their level is at least given level.
pub struct FilterLevel<D : Drain> {
    level: Level,
    drain : D,
}

impl<D : Drain> FilterLevel<D> {
    /// Create FilterLevel wrapping given `subdrain` and passing to it records
    /// only of at least `level`.
    pub fn new(level : Level, subdrain : D) -> Self {
        FilterLevel {
            level: level,
            drain: subdrain,
        }
    }
}

impl<D : Drain> Drain for FilterLevel<D> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        if info.level.is_at_least(self.level) {
            self.drain.log(info, logger_values, values)
        }
    }
}

/// Duplicate records into two drains
pub struct Duplicate<D1 : Drain, D2 : Drain> {
    drain1 : D1,
    drain2 : D2,
}

impl<D1 : Drain, D2 : Drain> Duplicate<D1, D2> {
    /// Create FilterLevel wrapping given `subdrain` and passing to it records
    /// only of at least `level`.
    pub fn new(drain1 : D1, drain2 : D2) -> Self {
        Duplicate {
            drain1: drain1,
            drain2: drain2,
        }
    }
}

impl<D1 : Drain, D2 : Drain> Drain for Duplicate<D1, D2> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        self.drain1.log(info, logger_values, values);
        self.drain2.log(info, logger_values, values);
    }
}

enum AsyncIoMsg{
    Bytes(Vec<u8>),
    Flush,
    Eof
}

/// Asynchronous io::Writer
///
/// Wraps an `io::Writer` and writes to it in separate thread
/// using channel to send the data.
///
/// This makes logging not block on potentially-slow IO operations.
pub struct AsyncIoWriter {
    sender : mpsc::Sender<AsyncIoMsg>,
    join : Option<thread::JoinHandle<()>>,
}

impl AsyncIoWriter {
    /// Create `AsyncIoWriter`
    pub fn new<W : io::Write+Send+'static>(mut io : W) -> Self {
        let (tx, rx) = mpsc::channel();
        let join = thread::spawn(move || {
            loop {
                match rx.recv().unwrap() {
                    AsyncIoMsg::Bytes(buf) => io.write_all(&buf).unwrap(),
                    AsyncIoMsg::Flush => io.flush().unwrap(),
                    AsyncIoMsg::Eof => return,
                }
            }
        });

        AsyncIoWriter {
            sender: tx,
            join: Some(join),
        }
    }
}

impl io::Write for AsyncIoWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let _ = self.sender.send(AsyncIoMsg::Bytes(buf.to_vec())).unwrap();
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        let _ = self.sender.send(AsyncIoMsg::Flush);
        Ok(())
    }
}

impl Drop for AsyncIoWriter {
    fn drop(&mut self) {
        let _ = self.sender.send(AsyncIoMsg::Eof);
        let _ = self.join.take().unwrap().join();
    }
}

/// Create AsyncIoWriter
pub fn async<W : io::Write + Send + 'static>(io : W) -> AsyncIoWriter {
    AsyncIoWriter::new(io)
}

/// Create Streamer drain
pub fn stream<W : io::Write + Send, F : format::Format>(io : W, format : F) -> Streamer<W, F> {
    Streamer::new(io, format)
}

/// Create FilterLevel drain
pub fn filter_level<D : Drain>(level : Level, d : D) -> FilterLevel<D> {
    FilterLevel::new(level, d)
}

/// Create Duplicate drain
pub fn duplicate<D1 : Drain, D2 : Drain>(d1 : D1, d2 : D2) -> Duplicate<D1, D2> {
    Duplicate::new(d1, d2)
}
<commit_msg>docs: Add warning about droping `AsyncIoWriter`<commit_after>//! # Drains
//!
//! Drains are responsible for filtering, formatting and writing the log records
//! into given destination.
use super::{Level};
use super::format;
use super::logger::RecordInfo;
use std::{io, str};
use std::sync::Mutex;
use super::{OwnedKeyValue,BorrowedKeyValue};
use std::sync::mpsc;
use std::thread;

///
/// Drain for Loggers
///
/// Implementing this trait allows writing own Drains
pub trait Drain : Send+Sync {
    /// Write one logging record
    fn log(&self, info : &RecordInfo, &[OwnedKeyValue], &[BorrowedKeyValue]);
}

/// Drain formating records and writing them to a byte-stream (io::Write)
///
/// Uses mutex to serialize writes.
/// TODO: Add one that does not serialize?
pub struct Streamer<W : io::Write, F : format::Format> {
    io : Mutex<W>,
    format : F,
}

impl<W : io::Write, F : format::Format> Streamer<W, F> {
    /// Create new `Streamer` writing to `io` using `format`
    pub fn new(io : W, format : F) -> Self {
        Streamer {
            io: Mutex::new(io),
            format : format,
        }
    }
}

impl<W : 'static+io::Write+Send, F : format::Format+Send> Drain for Streamer<W, F> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        let formatted = self.format.format(info, logger_values, values);

        let mut io = self.io.lock().unwrap();
        let _ = write!(io, "{}", formatted);
    }
}

/// Record log level filter
///
/// Wraps a drain and passes records to it, only
/// if their level is at least given level.
pub struct FilterLevel<D : Drain> {
    level: Level,
    drain : D,
}

impl<D : Drain> FilterLevel<D> {
    /// Create FilterLevel wrapping given `subdrain` and passing to it records
    /// only of at least `level`.
    pub fn new(level : Level, subdrain : D) -> Self {
        FilterLevel {
            level: level,
            drain: subdrain,
        }
    }
}

impl<D : Drain> Drain for FilterLevel<D> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        if info.level.is_at_least(self.level) {
            self.drain.log(info, logger_values, values)
        }
    }
}

/// Duplicate records into two drains
pub struct Duplicate<D1 : Drain, D2 : Drain> {
    drain1 : D1,
    drain2 : D2,
}

impl<D1 : Drain, D2 : Drain> Duplicate<D1, D2> {
    /// Create FilterLevel wrapping given `subdrain` and passing to it records
    /// only of at least `level`.
    pub fn new(drain1 : D1, drain2 : D2) -> Self {
        Duplicate {
            drain1: drain1,
            drain2: drain2,
        }
    }
}

impl<D1 : Drain, D2 : Drain> Drain for Duplicate<D1, D2> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        self.drain1.log(info, logger_values, values);
        self.drain2.log(info, logger_values, values);
    }
}

enum AsyncIoMsg{
    Bytes(Vec<u8>),
    Flush,
    Eof
}

/// Asynchronous io::Writer
///
/// Wraps an `io::Writer` and writes to it in separate thread
/// using channel to send the data.
///
/// This makes logging not block on potentially-slow IO operations.
///
/// Note: Dropping `AsyncIoWriter` waits for it's io-thread to finish.
/// If you can't tolerate the delay, make sure to use `Logger::
pub struct AsyncIoWriter {
    sender : mpsc::Sender<AsyncIoMsg>,
    join : Option<thread::JoinHandle<()>>,
}

impl AsyncIoWriter {
    /// Create `AsyncIoWriter`
    pub fn new<W : io::Write+Send+'static>(mut io : W) -> Self {
        let (tx, rx) = mpsc::channel();
        let join = thread::spawn(move || {
            loop {
                match rx.recv().unwrap() {
                    AsyncIoMsg::Bytes(buf) => io.write_all(&buf).unwrap(),
                    AsyncIoMsg::Flush => io.flush().unwrap(),
                    AsyncIoMsg::Eof => return,
                }
            }
        });

        AsyncIoWriter {
            sender: tx,
            join: Some(join),
        }
    }
}

impl io::Write for AsyncIoWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let _ = self.sender.send(AsyncIoMsg::Bytes(buf.to_vec())).unwrap();
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        let _ = self.sender.send(AsyncIoMsg::Flush);
        Ok(())
    }
}

impl Drop for AsyncIoWriter {
    fn drop(&mut self) {
        let _ = self.sender.send(AsyncIoMsg::Eof);
        let _ = self.join.take().unwrap().join();
    }
}

/// Create AsyncIoWriter
pub fn async<W : io::Write + Send + 'static>(io : W) -> AsyncIoWriter {
    AsyncIoWriter::new(io)
}

/// Create Streamer drain
pub fn stream<W : io::Write + Send, F : format::Format>(io : W, format : F) -> Streamer<W, F> {
    Streamer::new(io, format)
}

/// Create FilterLevel drain
pub fn filter_level<D : Drain>(level : Level, d : D) -> FilterLevel<D> {
    FilterLevel::new(level, d)
}

/// Create Duplicate drain
pub fn duplicate<D1 : Drain, D2 : Drain>(d1 : D1, d2 : D2) -> Duplicate<D1, D2> {
    Duplicate::new(d1, d2)
}
<|endoftext|>


<commit_before>use cocoa::base::{YES, id, nil};
use cocoa::foundation::NSString;
use std::borrow::Cow;
use std::convert::AsRef;
use std::ffi::CStr;
#[cfg(feature = "time2")]
use std::time::Instant;
use sys::{MTLCommandBuffer, MTLCommandBufferStatus};
use {AsRaw, Drawable};

pub struct CommandBuffer(id);

impl CommandBuffer {
    pub fn enqueue(&mut self) {
        unsafe { self.0.enqueue() }
    }

    pub fn commit(&mut self) -> Result<(), CommandBufferError> {
        unsafe {
            self.0.commit();
            let error = self.0.error();
            if error != nil { Err(CommandBufferError) } else { Ok(()) }
        }
    }

    pub fn present_drawable(&mut self, drawable: &mut Drawable) {
        unsafe { self.0.presentDrawable(*drawable.as_raw_mut()) }
    }

    #[cfg(feature = "time2")]
    pub fn present_drawable_at_time(&mut self, drawable: &mut Drawable, time: Instant) {
        unsafe { self.0.presentDrawable(*drawable.as_raw_mut(), time.elapsed().as_seconds()) }
    }

    pub fn present_drawable_at_time_secs(&mut self, drawable: &mut Drawable, time: f64) {
        unsafe { self.0.presentDrawable_atTime(*drawable.as_raw_mut(), time) }
    }

    pub fn wait_until_scheduled(&mut self) {
        unsafe { self.0.waitUntilScheduled() }
    }

    pub fn wait_until_completed(&mut self) {
        unsafe { self.0.waitUntilCompleted() }
    }

    pub fn get_status(&self) -> CommandBufferStatus {
        unsafe { self.0.status().into() }
    }

    pub fn has_retained_references(&self) -> bool {
        unsafe { self.0.retainedReferences() == YES }
    }

    pub fn set_label<S: AsRef<str>>(&mut self, label: S) {
        unsafe { MTLCommandBuffer::setLabel(self.0, NSString::alloc(nil).init_str(label.as_ref())) }
    }

    pub fn get_label(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(MTLCommandBuffer::label(self.0).UTF8String()).to_string_lossy() }
    }
}

impl_from_into_raw!(CommandBuffer, of protocol "MTLCommandBuffer");

convertible_enum! {
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    enum CommandBufferStatus : MTLCommandBufferStatus {
        CommandBufferStatusNotEnqueued => MTLCommandBufferStatusNotEnqueued,
        CommandBufferStatusEnqueued => MTLCommandBufferStatusEnqueued,
        CommandBufferStatusCommitted => MTLCommandBufferStatusCommitted,
        CommandBufferStatusScheduled => MTLCommandBufferStatusScheduled,
        CommandBufferStatusCompleted => MTLCommandBufferStatusCompleted,
        CommandBufferStatusError => MTLCommandBufferStatusError
    }
}

pub struct CommandBufferError;
<commit_msg>impl Send + Sync for CommandBuffer<commit_after>use cocoa::base::{YES, id, nil};
use cocoa::foundation::NSString;
use std::borrow::Cow;
use std::convert::AsRef;
use std::ffi::CStr;
#[cfg(feature = "time2")]
use std::time::Instant;
use sys::{MTLCommandBuffer, MTLCommandBufferStatus};
use {AsRaw, Drawable};

pub struct CommandBuffer(id);

unsafe impl Send for CommandBuffer {}
unsafe impl Sync for CommandBuffer {}

impl CommandBuffer {
    pub fn enqueue(&mut self) {
        unsafe { self.0.enqueue() }
    }

    pub fn commit(&mut self) -> Result<(), CommandBufferError> {
        unsafe {
            self.0.commit();
            let error = self.0.error();
            if error != nil { Err(CommandBufferError) } else { Ok(()) }
        }
    }

    pub fn present_drawable(&mut self, drawable: &mut Drawable) {
        unsafe { self.0.presentDrawable(*drawable.as_raw_mut()) }
    }

    #[cfg(feature = "time2")]
    pub fn present_drawable_at_time(&mut self, drawable: &mut Drawable, time: Instant) {
        unsafe { self.0.presentDrawable(*drawable.as_raw_mut(), time.elapsed().as_seconds()) }
    }

    pub fn present_drawable_at_time_secs(&mut self, drawable: &mut Drawable, time: f64) {
        unsafe { self.0.presentDrawable_atTime(*drawable.as_raw_mut(), time) }
    }

    pub fn wait_until_scheduled(&mut self) {
        unsafe { self.0.waitUntilScheduled() }
    }

    pub fn wait_until_completed(&mut self) {
        unsafe { self.0.waitUntilCompleted() }
    }

    pub fn get_status(&self) -> CommandBufferStatus {
        unsafe { self.0.status().into() }
    }

    pub fn has_retained_references(&self) -> bool {
        unsafe { self.0.retainedReferences() == YES }
    }

    pub fn set_label<S: AsRef<str>>(&mut self, label: S) {
        unsafe { MTLCommandBuffer::setLabel(self.0, NSString::alloc(nil).init_str(label.as_ref())) }
    }

    pub fn get_label(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(MTLCommandBuffer::label(self.0).UTF8String()).to_string_lossy() }
    }
}

impl_from_into_raw!(CommandBuffer, of protocol "MTLCommandBuffer");

convertible_enum! {
    #[derive(Clone, Copy, Eq, Hash, PartialEq)]
    enum CommandBufferStatus : MTLCommandBufferStatus {
        CommandBufferStatusNotEnqueued => MTLCommandBufferStatusNotEnqueued,
        CommandBufferStatusEnqueued => MTLCommandBufferStatusEnqueued,
        CommandBufferStatusCommitted => MTLCommandBufferStatusCommitted,
        CommandBufferStatusScheduled => MTLCommandBufferStatusScheduled,
        CommandBufferStatusCompleted => MTLCommandBufferStatusCompleted,
        CommandBufferStatusError => MTLCommandBufferStatusError
    }
}

pub struct CommandBufferError;
<|endoftext|>


<commit_before>use errors::*;
use libc::c_int;
use libmodbus_sys;
use modbus::Modbus;
use std::ffi::CString;

/// The TCP backend implements a Modbus variant used for communications over TCP/IPv4 networks.
/// It does not require a checksum calculation as lower layer takes care of the same.
///
/// * Create a Modbus TCP context
///     - [`new_tcp()`](struct.Modbus.html#method.new_tcp)
///
pub trait ModbusTCP {
    fn new_tcp(ip: &str, port: u32) -> Result<Modbus>;
    fn tcp_listen(&self, num_connection: i32) -> Result<i32>;
}

impl ModbusTCP for Modbus {
    /// `new_tcp` - create a libmodbus context for TCP/IPv4
    ///
    /// The [`new_tcp()`](#method.new_tcp) function shall allocate and initialize a modbus_t structure
    /// to communicate with a Modbus TCP IPv4 server.
    /// The **ip** argument specifies the IP address of the server to which the client wants to
    /// establish a connection. A empty string `""` value can be used to listen any addresses in server mode.
    /// The **port** argument is the TCP port to use. Set the port to `MODBUS_TCP_DEFAULT_PORT`
    /// to use the default one (502). It’s convenient to use a port number greater than or
    /// equal to 1024 because it’s not necessary to have administrator privileges.
    ///
    /// # Examples
    ///
    /// ```
    /// use libmodbus_rs::{Modbus, ModbusTCP, MODBUS_TCP_DEFAULT_PORT};
    ///
    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
    /// let modbus = Modbus::new_tcp("127.0.0.1", MODBUS_TCP_DEFAULT_PORT).unwrap();
    ///
    /// match modbus.connect() {
    ///     Ok(_) => {  }
    ///     Err(e) => println!("Error: {}", e),
    /// }
    /// ```
    fn new_tcp(ip: &str,
                    port: u32) -> Result<Modbus> {
        unsafe {
            let ip = CString::new(ip).unwrap();
            let ctx = libmodbus_sys::modbus_new_tcp(ip.as_ptr(),
                port as c_int);

            if ctx.is_null() {
                Err("Could not create new TCP Modbus contrext".into())
            } else {
                Ok(Modbus { ctx: ctx })
            }
        }
    }

    /// `tcp_listen` - create and listen a TCP Modbus socket (IPv4)
    ///
    /// # Parameters
    ///
    /// * `num_connection`  - maximum number of incoming connections on the specified IP address
    ///
    /// The [`tcp_listen()`](#method.tcp_listen) function shall create a socket and listen to maximum
    /// `num_connection` incoming connections on the specified IP address.
    /// If IP address is set to NULL or '0.0.0.0', any addresses will be listen.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use libmodbus_rs::{Modbus, ModbusTCP, MODBUS_TCP_DEFAULT_PORT};
    ///
    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
    ///
    /// let socket = modbus.tcp_listen(1);
    /// ```
    fn tcp_listen(&self, num_connection: i32) -> Result<i32> {
        unsafe {
            match libmodbus_sys::modbus_tcp_listen(self.ctx, num_connection) {
                -1 => Err("Could not listen on tcp port".into()),
                socket => Ok(socket),
            }
        }
    }
}
<commit_msg>Add Modbus::tcp_accept()<commit_after>use errors::*;
use libc::c_int;
use libmodbus_sys;
use modbus::Modbus;
use std::ffi::CString;

/// The TCP backend implements a Modbus variant used for communications over TCP/IPv4 networks.
/// It does not require a checksum calculation as lower layer takes care of the same.
///
/// * Create a Modbus TCP context
///     - [`new_tcp()`](struct.Modbus.html#method.new_tcp)
///
pub trait ModbusTCP {
    fn new_tcp(ip: &str, port: u32) -> Result<Modbus>;
    fn tcp_accept(&mut self, socket: &mut i32) -> Result<i32>;
    fn tcp_listen(&mut self, num_connection: i32) -> Result<i32>;
}

impl ModbusTCP for Modbus {
    /// `new_tcp` - create a libmodbus context for TCP/IPv4
    ///
    /// The [`new_tcp()`](#method.new_tcp) function shall allocate and initialize a modbus_t structure
    /// to communicate with a Modbus TCP IPv4 server.
    /// The **ip** argument specifies the IP address of the server to which the client wants to
    /// establish a connection. A empty string `""` value can be used to listen any addresses in server mode.
    /// The **port** argument is the TCP port to use. Set the port to `MODBUS_TCP_DEFAULT_PORT`
    /// to use the default one (502). It’s convenient to use a port number greater than or
    /// equal to 1024 because it’s not necessary to have administrator privileges.
    ///
    /// # Examples
    ///
    /// ```
    /// use libmodbus_rs::{Modbus, ModbusTCP, MODBUS_TCP_DEFAULT_PORT};
    ///
    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
    /// let modbus = Modbus::new_tcp("127.0.0.1", MODBUS_TCP_DEFAULT_PORT).unwrap();
    ///
    /// match modbus.connect() {
    ///     Ok(_) => {  }
    ///     Err(e) => println!("Error: {}", e),
    /// }
    /// ```
    fn new_tcp(ip: &str,
                    port: u32) -> Result<Modbus> {
        unsafe {
            let ip = CString::new(ip).unwrap();
            let ctx = libmodbus_sys::modbus_new_tcp(ip.as_ptr(),
                port as c_int);

            if ctx.is_null() {
                Err("Could not create new TCP Modbus contrext".into())
            } else {
                Ok(Modbus { ctx: ctx })
            }
        }
    }

    /// `tcp_accept` - accept a new connection on a TCP Modbus socket (IPv4)
    ///
    /// # Parameters
    ///
    /// * `socket`  - Socket
    ///
    /// The [`tcp_accept()`](#method.tcp_accept) function shall extract the first connection on the
    /// queue of pending connections and create a new socket given as argument.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use libmodbus_rs::{Modbus, ModbusTCP, MODBUS_TCP_DEFAULT_PORT};
    ///
    /// let mut modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
    /// let mut socket = modbus.tcp_listen(1).unwrap();
    ///
    /// modbus.tcp_accept(&mut socket);
    /// ```
    fn tcp_accept(&mut self, socket: &mut i32) -> Result<i32> {
        unsafe {
            match libmodbus_sys::modbus_tcp_accept(self.ctx, socket) {
                -1 => Err("Could not accept on TCP".into()),
                socket => Ok(socket),
            }
        }
    }

    /// `tcp_listen` - create and listen a TCP Modbus socket (IPv4)
    ///
    /// # Parameters
    ///
    /// * `num_connection`  - maximum number of incoming connections on the specified IP address
    ///
    /// The [`tcp_listen()`](#method.tcp_listen) function shall create a socket and listen to maximum
    /// `num_connection` incoming connections on the specified IP address.
    /// If IP address is set to NULL or '0.0.0.0', any addresses will be listen.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use libmodbus_rs::{Modbus, ModbusTCP, MODBUS_TCP_DEFAULT_PORT};
    ///
    /// let mut modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
    ///
    /// let socket = modbus.tcp_listen(1);
    /// ```
    fn tcp_listen(&mut self, num_connection: i32) -> Result<i32> {
        unsafe {
            match libmodbus_sys::modbus_tcp_listen(self.ctx, num_connection) {
                -1 => Err("Could not listen on tcp port".into()),
                socket => Ok(socket),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;

use linked_hash_map::LinkedHashMap;

use crate::input::Input;

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Id {
    pub input: Input,
    pub local: usize,
}
impl Id {
    pub fn new(input: Input, local: usize) -> Self {
        Self { input, local }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Ast {
    pub id: Id,
    pub kind: AstKind,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum AstKind {
    Int(Int),
    Text(Text),
    Identifier(Identifier),
    Symbol(Symbol),
    Struct(Struct),
    Lambda(Lambda),
    Call(Call),
    Assignment(Assignment),
    Error,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Int(pub u64);

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Text(pub AstString);

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Identifier(pub AstString);

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Symbol(pub AstString);

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Struct {
    pub entries: LinkedHashMap<Ast, Ast>,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Lambda {
    pub parameters: Vec<AstString>,
    pub body: Vec<Ast>,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Call {
    pub name: AstString,
    pub arguments: Vec<Ast>,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Assignment {
    pub name: AstString,
    pub body: Vec<Ast>,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct AstString {
    pub id: Id,
    pub value: String,
}
impl Deref for AstString {
    type Target = String;
    fn deref(&self) -> &Self::Target {
        &self.value
    }
}
<commit_msg>feat(compiler): impl Display for ast::Id<commit_after>use std::{
    fmt::{self, Display, Formatter},
    ops::Deref,
};

use linked_hash_map::LinkedHashMap;

use crate::input::Input;

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Id {
    pub input: Input,
    pub local: usize,
}
impl Id {
    pub fn new(input: Input, local: usize) -> Self {
        Self { input, local }
    }
}
impl Display for Id {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "AstId({}:{:?})", self.input, self.local)
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Ast {
    pub id: Id,
    pub kind: AstKind,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum AstKind {
    Int(Int),
    Text(Text),
    Identifier(Identifier),
    Symbol(Symbol),
    Struct(Struct),
    Lambda(Lambda),
    Call(Call),
    Assignment(Assignment),
    Error,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Int(pub u64);

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Text(pub AstString);

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Identifier(pub AstString);

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Symbol(pub AstString);

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Struct {
    pub entries: LinkedHashMap<Ast, Ast>,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Lambda {
    pub parameters: Vec<AstString>,
    pub body: Vec<Ast>,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Call {
    pub name: AstString,
    pub arguments: Vec<Ast>,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct Assignment {
    pub name: AstString,
    pub body: Vec<Ast>,
}

#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct AstString {
    pub id: Id,
    pub value: String,
}
impl Deref for AstString {
    type Target = String;
    fn deref(&self) -> &Self::Target {
        &self.value
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;

#[derive(Debug)]
pub enum ParseError {
    PeekError,
    /// Wraps any errors that might arise from the input
    InputError(Box<Error>),
}

impl ParseError {
    pub(crate) fn from_error<E>(err: E) -> Self
    where
        E: Error + 'static,
    {
        ParseError::InputError(Box::new(err))
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ParseError::InputError(ref err) => write!(f, "{}", err),
            &ParseError::PeekError => Ok(()),
        }
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match self {
            &ParseError::InputError(ref err) => err.description(),
            &ParseError::PeekError => "",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ParseError::InputError(ref err) => Some(err.as_ref()),
            _ => None,
        }
    }
}

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

    #[test]
    fn description_works() {
        let err = ParseError::from_error(io::Error::from(io::ErrorKind::BrokenPipe));
        let io_err = io::Error::from(io::ErrorKind::BrokenPipe);

        assert_eq!(err.description(), io_err.description());
    }

    #[test]
    fn display_works() {
        let err = ParseError::from_error(io::Error::from(io::ErrorKind::BrokenPipe));
        let io_err = io::Error::from(io::ErrorKind::BrokenPipe);

        assert_eq!(format!("{}", io_err), format!("{}", err));
    }
}<commit_msg>Add test for ParseError::PeekError<commit_after>use std::error::Error;
use std::fmt;

#[derive(Debug)]
pub enum ParseError {
    PeekError,
    /// Wraps any errors that might arise from the input
    InputError(Box<Error>),
}

impl ParseError {
    pub(crate) fn from_error<E>(err: E) -> Self
    where
        E: Error + 'static,
    {
        ParseError::InputError(Box::new(err))
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ParseError::InputError(ref err) => write!(f, "{}", err),
            &ParseError::PeekError => Ok(()),
        }
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match self {
            &ParseError::InputError(ref err) => err.description(),
            &ParseError::PeekError => "",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ParseError::InputError(ref err) => Some(err.as_ref()),
            _ => None,
        }
    }
}

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

    #[test]
    fn description_works() {
        let err = ParseError::from_error(io::Error::from(io::ErrorKind::BrokenPipe));
        let io_err = io::Error::from(io::ErrorKind::BrokenPipe);

        assert_eq!(io_err.description(), err.description());
        assert_eq!("", ParseError::PeekError.description());
    }

    #[test]
    fn display_works() {
        let err = ParseError::from_error(io::Error::from(io::ErrorKind::BrokenPipe));
        let io_err = io::Error::from(io::ErrorKind::BrokenPipe);

        assert_eq!(format!("{}", io_err), format!("{}", err));
        assert_eq!("".to_string(), format!("{}", ParseError::PeekError));
    }
}<|endoftext|>


<commit_before>use std::fmt;
use std::result;
use std::error::Error;
use std::io;

#[derive(Debug)]
pub enum BertError {
    // io errors
    IoError(io::Error),

    // parsing errors
    InvalidMagicNumber(usize),
    InvalidTag(usize, u8),
    InvalidFloat(usize),
    InvalidUTF8Atom(usize),
    InvalidLatin1Atom(usize),
    ExtraData(usize),
    VarintTooLarge(usize),
    NotEnoughData { offset: usize, needed: usize, available: usize }
}

impl BertError {
    fn offset(&self) -> Option<usize> {
        use self::BertError::*;
        match *self {
            InvalidMagicNumber(offset)
            | InvalidTag(offset, _)
            | InvalidFloat(offset)
            | InvalidUTF8Atom(offset)
            | InvalidLatin1Atom(offset)
            | ExtraData(offset)
            | VarintTooLarge(offset)
            | NotEnoughData { offset, .. } => Some(offset),

            _ => None
        }
    }

    fn extra_info(&self) -> Option<String> {
        use self::BertError::*;
        match *self {
            InvalidTag(_, tag) => Some(format!("{}", tag)),
            NotEnoughData { needed, available, .. } =>
                Some(format!("needed {} bytes, only {} available", needed, available)),
            _ => None
        }
    }
}

pub type Result<T> = result::Result<T, BertError>;

impl fmt::Display for BertError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.offset() {
            Some(offset) =>
                write!(f, "{} at offset {}", self.description(), offset)?,
            None =>
                write!(f, "{}", self.description())?
        }
        match self.extra_info() {
            None => write!(f, ""),
            Some(ref s) => write!(f, ": {}", s)
        }
    }
}

impl Error for BertError {
    fn description(&self) -> &str {
        use self::BertError::*;
        match *self {
            IoError(ref io_err) => io_err.description(),
            InvalidMagicNumber(_) => "invalid magic number",
            InvalidTag(_, _) => "invalid tag",
            InvalidFloat(_) => "invalid float",
            InvalidUTF8Atom(_) => "UTF-8 atom is not correctly encoded",
            InvalidLatin1Atom(_) => "Latin-1 atom is not correctly encoded",
            ExtraData(_) => "extra data after the BERT term",
            VarintTooLarge(_) => "varint is too large (greater than 2^64-1)",
            NotEnoughData { .. } => "no enough data is available",
        }
    }
}

impl From<io::Error> for BertError {
    fn from(io_err: io::Error) -> BertError {
        BertError::IoError(io_err)
    }
}
<commit_msg>Change NotEnoughData message<commit_after>use std::fmt;
use std::result;
use std::error::Error;
use std::io;

#[derive(Debug)]
pub enum BertError {
    // io errors
    IoError(io::Error),

    // parsing errors
    InvalidMagicNumber(usize),
    InvalidTag(usize, u8),
    InvalidFloat(usize),
    InvalidUTF8Atom(usize),
    InvalidLatin1Atom(usize),
    ExtraData(usize),
    VarintTooLarge(usize),
    NotEnoughData { offset: usize, needed: usize, available: usize }
}

impl BertError {
    fn offset(&self) -> Option<usize> {
        use self::BertError::*;
        match *self {
            InvalidMagicNumber(offset)
            | InvalidTag(offset, _)
            | InvalidFloat(offset)
            | InvalidUTF8Atom(offset)
            | InvalidLatin1Atom(offset)
            | ExtraData(offset)
            | VarintTooLarge(offset)
            | NotEnoughData { offset, .. } => Some(offset),

            _ => None
        }
    }

    fn extra_info(&self) -> Option<String> {
        use self::BertError::*;
        match *self {
            InvalidTag(_, tag) => Some(format!("{}", tag)),
            NotEnoughData { needed, available, .. } =>
                Some(format!("bytes needed: {}; bytes available: {}", needed, available)),
            _ => None
        }
    }
}

pub type Result<T> = result::Result<T, BertError>;

impl fmt::Display for BertError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.offset() {
            Some(offset) =>
                write!(f, "{} at offset {}", self.description(), offset)?,
            None =>
                write!(f, "{}", self.description())?
        }
        match self.extra_info() {
            None => write!(f, ""),
            Some(ref s) => write!(f, ": {}", s)
        }
    }
}

impl Error for BertError {
    fn description(&self) -> &str {
        use self::BertError::*;
        match *self {
            IoError(ref io_err) => io_err.description(),
            InvalidMagicNumber(_) => "invalid magic number",
            InvalidTag(_, _) => "invalid tag",
            InvalidFloat(_) => "invalid float",
            InvalidUTF8Atom(_) => "UTF-8 atom is not correctly encoded",
            InvalidLatin1Atom(_) => "Latin-1 atom is not correctly encoded",
            ExtraData(_) => "extra data after the BERT term",
            VarintTooLarge(_) => "varint is too large (greater than 2^64-1)",
            NotEnoughData { .. } => "no enough data available",
        }
    }
}

impl From<io::Error> for BertError {
    fn from(io_err: io::Error) -> BertError {
        BertError::IoError(io_err)
    }
}
<|endoftext|>


<commit_before>use json::JsonValue;

use HTWError;
use Year;
use CourseId;
use Degree;
use Studygroup;
use FromJson;
use json_string;
use get_json;

const BASE_URL: &'static str = "https://www2.htw-dresden.de/~app/API/GetExams.php";

/// An exam, something to study for!
#[derive(Debug)]
pub struct Exam {
    pub title: String,
    pub exam_type: String,
    pub study_branch: String,
    pub day: String,
    pub start_time: String,
    pub end_time: String,
    pub examiner: String,
    pub next_chance: String,
    pub rooms: Vec<String>,
}

impl FromJson for Exam {
    fn from_json(json: JsonValue) -> Result<Self, HTWError> {
        let exam = Exam {
            title: json_string(&json, "Title")?,
            exam_type: json_string(&json, "ExamType")?,
            study_branch: json_string(&json, "StudyBranch")?,
            day: json_string(&json, "Day")?,
            start_time: json_string(&json, "StartTime")?,
            end_time: json_string(&json, "EndTime")?,
            examiner: json_string(&json, "Examiner")?,
            next_chance: json_string(&json, "NextChance")?,
            rooms: vec![String::new()], // TODO
        };

        Ok(exam)
    }
}

impl Exam {
    /// Returns a list of `Exam`s for a given study group.
    ///
    /// # Arguments
    ///
    /// * `group` - Studygroup
    ///
    /// # Example
    ///
    /// ```
    /// use htwdresden::{Degree, Studygroup, Exam};
    ///
    /// let group = Studygroup { year: 2016, course: 121, group: 61, degree: Degree::Bachelor };
    /// let exams = Exam::for_studygroup(&group);
    /// ```
    pub fn for_studygroup(group: &Studygroup) -> Result<Vec<Exam>, HTWError> {
        Exam::for_student(group.year, group.course, group.degree)
    }

    /// Returns a list of `Exam`s for a given student.
    ///
    /// # Arguments
    ///
    /// * `year` - Year
    /// * `course` - Course identifier
    /// * `degree` - Degree
    ///
    /// # Example
    ///
    /// ```
    /// use htwdresden::{Degree, Exam};
    ///
    /// let exams = Exam::for_student(2016, 121, Degree::Bachelor);
    /// ```
    pub fn for_student(year: Year,
                       course: CourseId,
                       degree: Degree)
                       -> Result<Vec<Exam>, HTWError> {
        let url = format!("{base}?StgJhr={year}&Stg={course}&AbSc={degree}",
                          base = BASE_URL,
                          year = year,
                          course = course,
                          degree = degree.short());

        let json = get_json(&url);
        Ok(Exam::mult_from_json(json)?)
    }

    /// Returns a list of `Exam`s for a given professor.
    ///
    /// # Arguments
    ///
    /// * `prof` - Professor name
    ///
    /// # Example
    ///
    /// ```
    /// use htwdresden::Exam;
    ///
    /// let exams = Exam::for_prof("Rennekamp");
    /// ```
    pub fn for_prof(prof: &str) -> Result<Vec<Exam>, HTWError> {
        let url = format!("{base}?Prof={prof}", base = BASE_URL, prof = prof);
        let json = get_json(&url);
        Ok(Exam::mult_from_json(json)?)
    }
}
<commit_msg>parse exam rooms<commit_after>use json::JsonValue;

use HTWError;
use Year;
use CourseId;
use Degree;
use Studygroup;
use FromJson;
use json_string;
use get_json;

const BASE_URL: &'static str = "https://www2.htw-dresden.de/~app/API/GetExams.php";

/// An exam, something to study for!
#[derive(Debug)]
pub struct Exam {
    pub title: String,
    pub exam_type: String,
    pub study_branch: String,
    pub day: String,
    pub start_time: String,
    pub end_time: String,
    pub examiner: String,
    pub next_chance: String,
    pub rooms: Vec<String>,
}

impl FromJson for Exam {
    fn from_json(json: JsonValue) -> Result<Self, HTWError> {
        let arr = match json["Rooms"].clone() {
            JsonValue::Array(arr) => arr,
            _ => return Err(HTWError::Decoding("Rooms")),
        };
        let rooms: Vec<String> = arr.iter()
            .map(|room| String::from(room.as_str().expect("Rooms should be listed as Strings :/")))
            .collect();

        let exam = Exam {
            title: json_string(&json, "Title")?,
            exam_type: json_string(&json, "ExamType")?,
            study_branch: json_string(&json, "StudyBranch")?,
            day: json_string(&json, "Day")?,
            start_time: json_string(&json, "StartTime")?,
            end_time: json_string(&json, "EndTime")?,
            examiner: json_string(&json, "Examiner")?,
            next_chance: json_string(&json, "NextChance")?,
            rooms: rooms,
        };

        Ok(exam)
    }
}

impl Exam {
    /// Returns a list of `Exam`s for a given study group.
    ///
    /// # Arguments
    ///
    /// * `group` - Studygroup
    ///
    /// # Example
    ///
    /// ```
    /// use htwdresden::{Degree, Studygroup, Exam};
    ///
    /// let group = Studygroup { year: 2016, course: 121, group: 61, degree: Degree::Bachelor };
    /// let exams = Exam::for_studygroup(&group);
    /// ```
    pub fn for_studygroup(group: &Studygroup) -> Result<Vec<Exam>, HTWError> {
        Exam::for_student(group.year, group.course, group.degree)
    }

    /// Returns a list of `Exam`s for a given student.
    ///
    /// # Arguments
    ///
    /// * `year` - Year
    /// * `course` - Course identifier
    /// * `degree` - Degree
    ///
    /// # Example
    ///
    /// ```
    /// use htwdresden::{Degree, Exam};
    ///
    /// let exams = Exam::for_student(2016, 121, Degree::Bachelor);
    /// ```
    pub fn for_student(year: Year,
                       course: CourseId,
                       degree: Degree)
                       -> Result<Vec<Exam>, HTWError> {
        let url = format!("{base}?StgJhr={year}&Stg={course}&AbSc={degree}",
                          base = BASE_URL,
                          year = year,
                          course = course,
                          degree = degree.short());

        let json = get_json(&url);
        Ok(Exam::mult_from_json(json)?)
    }

    /// Returns a list of `Exam`s for a given professor.
    ///
    /// # Arguments
    ///
    /// * `prof` - Professor name
    ///
    /// # Example
    ///
    /// ```
    /// use htwdresden::Exam;
    ///
    /// let exams = Exam::for_prof("Rennekamp");
    /// ```
    pub fn for_prof(prof: &str) -> Result<Vec<Exam>, HTWError> {
        let url = format!("{base}?Prof={prof}", base = BASE_URL, prof = prof);
        let json = get_json(&url);
        Ok(Exam::mult_from_json(json)?)
    }
}
<|endoftext|>


<commit_before>extern crate num;
extern crate nalgebra as na;

pub const TOTAL_FLUIDS: usize = 2;
pub const NORMAL_DIFFUSION: [f64; 2] = [0.5, 1.0];

const TIMESTEP: f64 = 0.2;

#[derive(Default, Debug)]
pub struct Solution {
    pub fluids: [f64; TOTAL_FLUIDS],
    pub coefficients: [f64; TOTAL_FLUIDS],
    diffuse: [f64; TOTAL_FLUIDS],
}

impl Solution {
    pub fn new(fluids: [f64; TOTAL_FLUIDS], coefficients: [f64; TOTAL_FLUIDS]) -> Self {
        Solution {
            fluids: fluids,
            coefficients: coefficients,
            diffuse: [0.0; TOTAL_FLUIDS],
        }
    }

    pub fn react_deltas(&self) -> [f64; TOTAL_FLUIDS] {
        let a = self.fluids[1];
        let b = self.fluids[0];
        let f = 0.022;
        let k = 0.051;
        [a * b * b - (k + f) * b, -a * b * b + f * (1.0 - a)]
    }

    pub fn diffuse_from(&mut self, other: &Solution) {
        for i in 0..TOTAL_FLUIDS {
            self.diffuse[i] += other.fluids[i] * other.coefficients[i] / 6.0;
        }
    }

    pub fn end_cycle(&mut self) {
        let reacts = self.react_deltas();
        for i in 0..TOTAL_FLUIDS {
            self.fluids[i] += TIMESTEP *
                              (reacts[i] + self.diffuse[i] - self.coefficients[i] * self.fluids[i]);
            self.diffuse[i] = 0.0;
        }
    }
}
<commit_msg>interesting enough in U-skate<commit_after>extern crate num;
extern crate nalgebra as na;

pub const TOTAL_FLUIDS: usize = 2;
pub const NORMAL_DIFFUSION: [f64; 2] = [0.5, 1.0];

const TIMESTEP: f64 = 0.2;

#[derive(Default, Debug)]
pub struct Solution {
    pub fluids: [f64; TOTAL_FLUIDS],
    pub coefficients: [f64; TOTAL_FLUIDS],
    diffuse: [f64; TOTAL_FLUIDS],
}

impl Solution {
    pub fn new(fluids: [f64; TOTAL_FLUIDS], coefficients: [f64; TOTAL_FLUIDS]) -> Self {
        Solution {
            fluids: fluids,
            coefficients: coefficients,
            diffuse: [0.0; TOTAL_FLUIDS],
        }
    }

    pub fn react_deltas(&self) -> [f64; TOTAL_FLUIDS] {
        let a = self.fluids[1];
        let b = self.fluids[0];
        let f = 0.062;
        let k = 0.061;
        [a * b * b - (k + f) * b, -a * b * b + f * (1.0 - a)]
    }

    pub fn diffuse_from(&mut self, other: &Solution) {
        for i in 0..TOTAL_FLUIDS {
            self.diffuse[i] += other.fluids[i] * other.coefficients[i] / 6.0;
        }
    }

    pub fn end_cycle(&mut self) {
        let reacts = self.react_deltas();
        for i in 0..TOTAL_FLUIDS {
            self.fluids[i] += TIMESTEP *
                              (reacts[i] + self.diffuse[i] - self.coefficients[i] * self.fluids[i]);
            self.diffuse[i] = 0.0;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 by SiegeLord
//
// All rights reserved. Distributed under ZLib. For full terms see the file LICENSE.

use ffi::ALLEGRO_MIXER;
use mixer::Mixer;

use sync::Arc;
use std::sync::atomics::{AtomicBool, SeqCst};
use libc::c_void;

pub trait AttachToMixerImpl
{
	fn create_connection(&mut self, allegro_mixer: *mut ALLEGRO_MIXER) -> Option<Connection>;
}

pub trait HasMixer
{
	fn get_mixer<'l>(&'l self) -> &'l Mixer;
	fn get_mixer_mut<'l>(&'l mut self) -> &'l mut Mixer;
}

// When a connection is broken, the callback is called on the payload
pub struct Connection
{
	active: Arc<AtomicBool>,
	payload: *mut c_void,
	callback: fn(*mut c_void),
}

impl Connection
{
	pub fn new(payload: *mut c_void, callback: fn(*mut c_void)) -> (Connection, Connection)
	{
		let active1 = Arc::new(AtomicBool::new(true));
		let active2 = active1.clone();
		(Connection{ active: active1, payload: payload, callback: callback },
		 Connection{ active: active2, payload: payload, callback: callback })
	}
}

impl Drop for Connection
{
	fn drop(&mut self)
	{
		if self.active.swap(false, SeqCst)
		{
			(self.callback)(self.payload);
		}
	}
}
<commit_msg>Hide the module-private traits (rustdoc bug)<commit_after>// Copyright (c) 2014 by SiegeLord
//
// All rights reserved. Distributed under ZLib. For full terms see the file LICENSE.

use ffi::ALLEGRO_MIXER;
use mixer::Mixer;

use sync::Arc;
use std::sync::atomics::{AtomicBool, SeqCst};
use libc::c_void;

#[doc(hidden)]
pub trait AttachToMixerImpl
{
	fn create_connection(&mut self, allegro_mixer: *mut ALLEGRO_MIXER) -> Option<Connection>;
}

#[doc(hidden)]
pub trait HasMixer
{
	fn get_mixer<'l>(&'l self) -> &'l Mixer;
	fn get_mixer_mut<'l>(&'l mut self) -> &'l mut Mixer;
}

// When a connection is broken, the callback is called on the payload
pub struct Connection
{
	active: Arc<AtomicBool>,
	payload: *mut c_void,
	callback: fn(*mut c_void),
}

impl Connection
{
	pub fn new(payload: *mut c_void, callback: fn(*mut c_void)) -> (Connection, Connection)
	{
		let active1 = Arc::new(AtomicBool::new(true));
		let active2 = active1.clone();
		(Connection{ active: active1, payload: payload, callback: callback },
		 Connection{ active: active2, payload: payload, callback: callback })
	}
}

impl Drop for Connection
{
	fn drop(&mut self)
	{
		if self.active.swap(false, SeqCst)
		{
			(self.callback)(self.payload);
		}
	}
}
<|endoftext|>