<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` architecture-specific implementation.
// pub mod cpu;
pub mod drivers;
pub mod interrupts;
// pub mod memory;

#[path = "../x86_all/bda.rs"] pub mod bda;
#[path = "../x86_all/multiboot2.rs"] pub mod multiboot2;

use memory::PAddr;
<<<<<<< HEAD
pub const ARCH_BITS: u8 = 64;

/// Entry point for architecture-specific kernel init
pub fn arch_init(multiboot_addr: PAddr) {
    use multiboot2;
    use self::cpu::{control_regs, msr};
    use core::mem;
    use alloc::buddy;
    use memory::paging::{Page, PhysicalPage};
=======
use params::InitParams;
use ::kernel_init;

pub const ARCH_BITS: u8 = 64;

/// Entry point for architecture-specific kernel init
///
/// This expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) {
    use memory::arch::{HEAP_BASE, HEAP_TOP};

    ::io::term::CONSOLE.lock().clear();
    ::logger::initialize()
        .expect("Could not initialize logger!");
>>>>>>> origin/master

    // -- Unpack multiboot tag -----------------------------------------------
    let boot_info
        = unsafe { multiboot2::Info::from(multiboot_addr)
                    .expect("Could not unpack multiboot2 information!") };

    let mmap_tag // Extract the memory map tag from the multiboot info
        = boot_info.mem_map()
                   .expect("Memory map tag required!");

    kinfoln!(dots: " . ", "Detected memory areas:");
    for a in mmap_tag.areas() {
        kinfoln!(dots: " . . ", "start: {:#08x}, end: {:#08x}"
                , a.base, a.length );
    }

    let elf_sections_tag // Extract ELF sections tag from the multiboot info
        = boot_info.elf_sections()
                   .expect("ELF sections tag required!");

    kinfoln!(dots: " . ", "Detecting kernel ELF sections:");

    let kernel_begin    // Extract kernel ELF sections from  multiboot info
        = elf_sections_tag.sections()
            .map(|s| {
                kinfoln!( dots: " . . "
                     , "address: {:#08x}, size: {:#08x}, flags: {:#08x}"
                        , s.addr()
                        , s.length()
                        , s.flags() );
                s.addr() })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let mut n_elf_sections = 0;
    let kernel_end
        = elf_sections_tag.sections()
            .map(|s| { n_elf_sections += 1; s.addr() })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    kinfoln!( dots: " . ", "Detected {} kernel ELF sections.", n_elf_sections);
    kinfoln!(dots: " . . ", "Kernel begins at {:#x} and ends at {:#x}."
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as u64;

<<<<<<< HEAD
    println!( " . . Multiboot info begins at {:#x} and ends at {:#x}."
           , multiboot_addr, multiboot_end);

     // -- enable flags needed for paging ------------------------------------
     unsafe {
         control_regs::cr0::enable_write_protect(true);
         println!( " . Page write protect ENABED" );

         msr::enable_nxe();
         println!( " . Page no execute bit ENABLED");
     }

     println!(" . . Preparing to initialize heap. ");
     // -- initialize the heap -----------------------------------------------
     let heap_base
        = PhysicalPage::containing_addr(PAddr::from(multiboot_addr + boot_info.length as u64)).base();
     unsafe {
         buddy::system::init_heap(heap_base.as_mut_ptr(), ::memory::HEAP_SIZE);
         println!( "{:<38}{:>40}\n \
                     . . Heap begins at {:#x} and ends at {:#x}"
                 , " . Intializing heap"
                // , ::memory::init_heap(heap_base.as_mut_ptr())
                //            .unwrap_or("[ FAIL ]")
                 , "[ OKAY ]"
                 , heap_base
                 , heap_base + ::memory::HEAP_SIZE as u64);
     };

    // -- remap the kernel ----------------------------------------------------
    println!(" . Remapping the kernel:");

    let frame_allocator = ::memory::alloc::BuddyFrameAllocator::new();
    ::memory::kernel_remap(&boot_info, &frame_allocator);
    println!("{:<38}{:>40}", " . Remapping the kernel", "[ OKAY ]");

=======
    kinfoln!(dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);
>>>>>>> origin/master

    let params = InitParams { kernel_base: kernel_begin
                            , kernel_top:  kernel_end
                            , heap_base:   unsafe { HEAP_BASE }
                            , heap_top:    unsafe { HEAP_TOP }
                            };
    kernel_init(params);
}
<commit_msg>[kernel] fix merge conflicts in x86_64 arch_init<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` architecture-specific implementation.
// pub mod cpu;
pub mod drivers;
pub mod interrupts;
// pub mod memory;

#[path = "../x86_all/bda.rs"] pub mod bda;
#[path = "../x86_all/multiboot2.rs"] pub mod multiboot2;

pub const ARCH_BITS: u8 = 64;

/// Entry point for architecture-specific kernel init
///
/// This expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) {
    use multiboot2;
    use cpu::{control_regs, msr};
    use core::mem;
    use alloc::buddy;
    use memory::{PAddr, Page, PhysicalPage};

    use memory::arch::{HEAP_BASE, HEAP_TOP};
    use params::InitParams;
    use ::kernel_init;

    ::io::term::CONSOLE.lock().clear();
    ::logger::initialize()
        .expect("Could not initialize logger!");

    // -- Unpack multiboot tag -----------------------------------------------
    let boot_info
        = unsafe { multiboot2::Info::from(multiboot_addr)
                    .expect("Could not unpack multiboot2 information!") };

    let mmap_tag // Extract the memory map tag from the multiboot info
        = boot_info.mem_map()
                   .expect("Memory map tag required!");

    kinfoln!(dots: " . ", "Detected memory areas:");
    for a in mmap_tag.areas() {
        kinfoln!( dots: " . . ", "start: {:#08x}, end: {:#08x}"
                , a.base, a.length );
    }

    let elf_sections_tag // Extract ELF sections tag from the multiboot info
        = boot_info.elf_sections()
                   .expect("ELF sections tag required!");

    kinfoln!(dots: " . ", "Detecting kernel ELF sections:");

    let kernel_begin    // Extract kernel ELF sections from  multiboot info
        = elf_sections_tag.sections()
            .map(|s| {
                kinfoln!( dots: " . . "
                        , "address: {:#08x}, size: {:#08x}, flags: {:#08x}"
                        , s.addr()
                        , s.length()
                        , s.flags() );
                s.addr() })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let mut n_elf_sections = 0;
    let kernel_end
        = elf_sections_tag.sections()
            .map(|s| { n_elf_sections += 1; s.addr() })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    kinfoln!( dots: " . ", "Detected {} kernel ELF sections.", n_elf_sections);
    kinfoln!( dots: " . . ", "Kernel begins at {:#x} and ends at {:#x}."
            , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as u64;

    kinfoln!( dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
            , multiboot_addr, multiboot_end);

     // -- enable flags needed for paging ------------------------------------
     unsafe {
         control_regs::cr0::enable_write_protect(true);
         kinfoln!(dots: " . ", "Page write protect ENABED" );

         msr::enable_nxe();
         kinfoln!(dots: " . ", "Page no execute bit ENABLED");
     }

     println!(" . . Preparing to initialize heap. ");
     // -- initialize the heap -----------------------------------------------
     let heap_base
        = PhysicalPage::containing_addr(PAddr::from(multiboot_addr + boot_info.length as u64)).base();
     unsafe {
         buddy::system::init_heap(heap_base.as_mut_ptr(), ::memory::HEAP_SIZE);
         println!( "{:<38}{:>40}\n \
                     . . Heap begins at {:#x} and ends at {:#x}"
                 , " . Intializing heap"
                // , ::memory::init_heap(heap_base.as_mut_ptr())
                //            .unwrap_or("[ FAIL ]")
                 , "[ OKAY ]"
                 , heap_base
                 , heap_base + ::memory::HEAP_SIZE as u64);
     };

    // -- remap the kernel ----------------------------------------------------
    kinfoln!(dots: " . ", "Remapping the kernel:");

    let frame_allocator = ::memory::alloc::BuddyFrameAllocator::new();
    ::memory::kernel_remap(&boot_info, &frame_allocator);
    kinfoln!(dots: " . ", "Remapping the kernel", "[ OKAY ]");

    kinfoln!(dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);

    let params = InitParams { kernel_base: kernel_begin
                            , kernel_top:  kernel_end
                            , heap_base:   unsafe { HEAP_BASE }
                            , heap_top:    unsafe { HEAP_TOP }
                            };
    kernel_init(params);
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Averages/Arithmetic_mean
use std::iter::AdditiveIterator;

// The mean is not defined for an empty list, so we must return an Option
fn mean(list: &[f64]) -> Option<f64> {
    match list.len() {
        0 => None,
        n => {
            let sum = list.iter().map(|&x| x).sum();
            Some(sum / n as f64)
        }
    }
}

#[cfg(not(test))]
fn main() {
    let input = vec!(3.0, 1.0, 4.0, 1.0, 5.0, 9.0);

    // This should be 3.833333
    let mean = mean(input.as_slice()).unwrap();
    println!("{}", mean);
}

#[test]
fn simple_test() {
    let vector = vec!(1.0, 2.0, 3.0, 4.0, 5.0);
    assert!(mean(vector.as_slice()).unwrap() == 3.0);
}

#[test]
fn mean_empty_list() {
    let empty_vec = vec!();
    assert!(mean(empty_vec.as_slice()).is_none());
}
<commit_msg>arithmetic mean: unnecessary vecs<commit_after>// Implements http://rosettacode.org/wiki/Averages/Arithmetic_mean
use std::iter::AdditiveIterator;

// The mean is not defined for an empty list, so we must return an Option
fn mean(list: &[f64]) -> Option<f64> {
    match list.len() {
        0 => None,
        n => {
            let sum = list.iter().map(|&x| x).sum();
            Some(sum / n as f64)
        }
    }
}

#[cfg(not(test))]
fn main() {
    let input = [3.0, 1.0, 4.0, 1.0, 5.0, 9.0];

    // This should be 3.833333
    let mean = mean(input).unwrap();
    println!("{}", mean);
}

#[test]
fn simple_test() {
    let nums = [1.0, 2.0, 3.0, 4.0, 5.0];
    assert_eq!(mean(nums), Some(3.0));
}

#[test]
fn mean_empty_list() {
    let no_nums = [];
    assert_eq!(mean(no_nums), None);
}
<|endoftext|>


<commit_before>//! Basic resource data handling.

use std::fmt;
use ::iana::Rtype;
use ::rdata::fmt_rdata;
use super::{Composer, ComposeResult, Parser, ParseResult};

//----------- RecordData -----------------------------------------------------

pub trait RecordData: Sized {
    /// Returns the record type for this record data instance.
    fn rtype(&self) -> Rtype;

    /// Appends the record data to the end of a composer.
    fn compose<C: AsMut<Composer>>(&self, mut target: C) -> ComposeResult<()>;
}

//------------ ParsedRecordData ----------------------------------------------

pub trait ParsedRecordData<'a>: RecordData {
    fn parse(rtype: Rtype, parser: &mut Parser<'a>)
             -> ParseResult<Option<Self>>;
}

//------------ GenericRecordData --------------------------------------------

#[derive(Clone, Debug)]
pub struct GenericRecordData<'a> {
    rtype: Rtype,
    parser: Parser<'a>,
}

impl<'a> GenericRecordData<'a> {
    fn reparse<D: ParsedRecordData<'a>>(&self) -> ParseResult<D> {
        D::parse(self.rtype, &mut self.parser.clone()).map(Option::unwrap)
    }
}

impl<'a> RecordData for GenericRecordData<'a> {
    fn rtype(&self) -> Rtype {
        self.rtype
    }

    fn compose<C: AsMut<Composer>>(&self, target: C) -> ComposeResult<()> {
        use ::rdata::rfc1035::parsed::*;

        match self.rtype {
            Rtype::A => try!(self.reparse::<A>()).compose(target),
            _ => unimplemented!()
        }
    }
}

impl<'a> ParsedRecordData<'a> for GenericRecordData<'a> {
    fn parse(rtype: Rtype, parser: &mut Parser<'a>)
             -> ParseResult<Option<Self>> {
        let my_parser = parser.clone();
        let len = parser.remaining();
        try!(parser.skip(len));
        Ok(Some(GenericRecordData {
            rtype: rtype,
            parser: my_parser
        }))
    }
}

impl<'a> fmt::Display for GenericRecordData<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt_rdata(self.rtype, &mut self.parser.clone(), f)
    }
}

<commit_msg>Add documentation to ::bits::rdata.<commit_after>//! Basic resource data handling.
//!
//! DNS resource records consist of some common data defining the domain
//! name they pertain to, their type and class, and finally record data
//! the format of which depends on the specific record type. As there are
//! currently more than eighty record types, having a giant enum for record
//! data seemed like a bad idea. Instead, resource records are generic over
//! two traits defined by this module. All concrete types implement
//! [`RecordData`]. Types that can be parsed out of messages also implement
//! [`ParsedRecordData`]. This distinction is only relevant for types that
//! contain and are generic over domain names: for these, parsing is only
//! available if the names use [`ParsedDName`].
//!
//! All concrete types shipped with this crate are implemented in the
//! [domain::rdata] module.
//!
//! In order to walk over all resource records in a message or work with
//! unknown record types, this module also defines the [`GenericRecordData`]
//! type that can deal with all record types but provides only a limited
//! functionality.
//!
//! [`RecordData`]: trait.RecordData.html
//! [`ParsedRecordData`]: trait.ParsedRecordData.html
//! [domain::rdata]: ../../rdata/index.html
//! [`GenericRecordData`]: struct.GenericRecordData.html

use std::fmt;
use ::iana::Rtype;
use ::rdata::fmt_rdata;
use super::{Composer, ComposeResult, Parser, ParseResult};

//----------- RecordData -----------------------------------------------------

/// A trait for types representing record data.
pub trait RecordData: Sized {
    /// Returns the record type for this record data instance.
    ///
    /// This is a method rather than an associated function to allow one
    /// type to be used for several real record types.
    fn rtype(&self) -> Rtype;

    /// Appends the record data to the end of a composer.
    fn compose<C: AsMut<Composer>>(&self, mut target: C) -> ComposeResult<()>;
}

//------------ ParsedRecordData ----------------------------------------------

/// A trait for types that allow parsing record data from a message.
pub trait ParsedRecordData<'a>: RecordData {
    /// Parses the record data out of a parser.
    fn parse(rtype: Rtype, parser: &mut Parser<'a>)
             -> ParseResult<Option<Self>>;
}

//------------ GenericRecordData --------------------------------------------

/// A type for parsing any type of record data.
///
/// This type accepts any record type and stores a reference to the plain
/// binary record data in the message. This way, it can later be converted
/// into concrete record data if necessary via the [`reparse()`] method.
///
/// Because the data referenced by a value may contain compressed domain
/// names, transitively building a new message from this data may lead to
/// corrupt messages. To avoid this sort of thing,
/// [RFC 3597], ‘Handling of Unknown DNS Resource Record (RR) Types,’
/// restricted compressed domain names to record types defined in [RFC 1035].
/// Accordingly, this types [`RecordData::compose()`] implementation treats
/// these types specially and ensures that their names are handles correctly.
/// This may still lead to corrupt messages, however, if the generic record
/// data is obtained from a source not complying with RFC 3597. In general,
/// be wary when re-composing parsed messages unseen.
///
/// [`RecordData::compose()`]: trait.RecordData.html#tymethod.compose
/// [RFC 1035]: https://tools.ietf.org/html/rfc1035
/// [RFC 3597]: https://tools.ietf.org/html/rfc3597
#[derive(Clone, Debug)]
pub struct GenericRecordData<'a> {
    /// The record type of this data.
    rtype: Rtype,

    /// A parser for the record’s data.
    ///
    /// The parser will be positioned at the beginning of the record data and
    /// will be limited to the length of the record data.
    parser: Parser<'a>,
}

impl<'a> GenericRecordData<'a> {
    /// Tries to re-parse the data for the given record data type.
    ///
    /// # Panics
    ///
    /// This method panics if the specified record data type does not
    /// actually feel like parsing data of the value’s record type.
    fn reparse<D: ParsedRecordData<'a>>(&self) -> ParseResult<D> {
        D::parse(self.rtype, &mut self.parser.clone()).map(Option::unwrap)
    }
}

impl<'a> RecordData for GenericRecordData<'a> {
    fn rtype(&self) -> Rtype {
        self.rtype
    }

    fn compose<C: AsMut<Composer>>(&self, mut target: C)
                        -> ComposeResult<()> {
        use ::rdata::rfc1035::parsed::*;

        match self.rtype {
            // Special treatment for any type from RFC 1035 that contains
            // domain names.
            Rtype::Cname => try!(self.reparse::<Cname>()).compose(target),
            Rtype::Mb => try!(self.reparse::<Mb>()).compose(target),
            Rtype::Md => try!(self.reparse::<Md>()).compose(target),
            Rtype::Mf => try!(self.reparse::<Mf>()).compose(target),
            Rtype::Mg => try!(self.reparse::<Mg>()).compose(target),
            Rtype::Minfo => try!(self.reparse::<Minfo>()).compose(target),
            Rtype::Mr => try!(self.reparse::<Mr>()).compose(target),
            Rtype::Mx => try!(self.reparse::<Mx>()).compose(target),
            Rtype::Ns => try!(self.reparse::<Ns>()).compose(target),
            Rtype::Ptr => try!(self.reparse::<Ptr>()).compose(target),
            Rtype::Soa => try!(self.reparse::<Soa>()).compose(target),

            // Anything else can go verbatim.
            _ => {
                let len = self.parser.remaining();
                let bytes = try!(self.parser.clone().parse_bytes(len));
                target.as_mut().compose_bytes(bytes)
            }
        }
    }
}

impl<'a> ParsedRecordData<'a> for GenericRecordData<'a> {
    fn parse(rtype: Rtype, parser: &mut Parser<'a>)
             -> ParseResult<Option<Self>> {
        let my_parser = parser.clone();
        let len = parser.remaining();
        try!(parser.skip(len));
        Ok(Some(GenericRecordData {
            rtype: rtype,
            parser: my_parser
        }))
    }
}

impl<'a> fmt::Display for GenericRecordData<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt_rdata(self.rtype, &mut self.parser.clone(), f)
    }
}

<|endoftext|>


<commit_before>//! Binary encoding for lambda expressions

use lambda_calculus::term::*;
use self::Error::*;

/// An error that can occur if the input stream of "bits" is not valid binary lambda calculus.
#[derive(Debug, PartialEq)]
pub enum Error {
    NotATerm
}

/// Parse a binary-encoded lambda `Term`.
///
/// # Example
/// ```
/// use blc::binary_encoding::{from_binary, to_binary};
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(to_binary(&k.unwrap()), Vec::from(&b"0000110"[..]));
/// ```
pub fn from_binary(input: &[u8]) -> Result<Term, Error> {
    if let Some((result, _)) = _from_binary(input) {
        Ok(result)
    } else {
        Err(NotATerm)
    }
}

fn _from_binary(input: &[u8]) -> Option<(Term, &[u8])> {
    if input.len() == 0 { return None }

    if [9, 10, 13, 32].contains(&input[0]) {
        _from_binary(&input[1..]) // skip whitespaces
    } else {
        match &input[0..2] {
            b"00" => {
                if let Some((term, rest)) = _from_binary(&input[2..]) {
                    Some((abs(term), rest))
                } else {
                    None
                }
            },
            b"01" => {
                if let Some((term1, rest1)) = _from_binary(&input[2..]) {
                    if let Some((term2, rest2)) = _from_binary(&rest1) {
                        Some((app(term1, term2), &rest2))
                    } else {
                        None
                    }
                } else {
                    None
                }
            },
            b"10" | b"11" => {
                let i = input.iter().take_while(|&b| *b == b'1').count();
                if input[2..].len() == 0 {
                    Some((Var(i), &*b""))
                } else {
                    Some((Var(i), &input[i+1..]))
                }
            },
            _ => None
        }
    }
}

/// Represent a lambda `Term` in binary.
///
/// # Example
/// ```
/// use blc::binary_encoding::{from_binary, to_binary};
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(to_binary(&k.unwrap()), Vec::from(&b"0000110"[..]));
/// ```
pub fn to_binary(term: &Term) -> Vec<u8> {
    let mut output = Vec::new();
    _to_binary(term, &mut output);

    output
}

fn _to_binary(term: &Term, output: &mut Vec<u8>) {
    match *term {
        Var(i) => {
            for _ in 0..i { output.push(b'1') }
            output.push(b'0');
        }
        Abs(ref t) => {
            output.extend_from_slice(b"00");
            output.append(&mut to_binary(t));
        }
        App(ref t1, ref t2) => {
            output.extend_from_slice(b"01");
            output.append(&mut to_binary(t1));
            output.append(&mut to_binary(t2));
        }
    }
}

/// Convert a stream of "bits" into bytes. It is not always reversible with `decompress`, because
/// it produces full bytes, while the length of its input can be indivisible by 8.
///
/// # Example
/// ```
/// use blc::binary_encoding::{compress};
///
/// let succ_compressed = compress(&*b"000000011100101111011010");
/// assert_eq!(succ_compressed, vec![0x1, 0xCB, 0xDA]);
/// ```
pub fn compress(binary: &[u8]) -> Vec<u8> {
    let length = binary.len();
    let mut output = Vec::with_capacity(length / 8 + 1);
    let mut pos = 0;

    while pos <= length - 8 {
        output.push(bits_to_byte(&binary[pos..(pos + 8)]));
        pos += 8;
    }

    if pos != length {
        let mut last_byte = Vec::with_capacity(8);
        last_byte.extend_from_slice(&binary[pos..]);
        for _ in 0..(8 - (length - pos)) { last_byte.push(b'0') }
        output.push(bits_to_byte(&last_byte));
    }

    output
}

fn bits_to_byte(bits: &[u8]) -> u8 {
    bits.iter().fold(0, |acc, &b| acc * 2 + (b - 48))
}

/// Convert bytes into "bits" suitable for binary lambda calculus purposes.
///
/// # Example
/// ```
/// use blc::binary_encoding::{decompress};
///
/// let succ_compressed = vec![0x1, 0xCB, 0xDA];
/// assert_eq!(decompress(&succ_compressed), b"000000011100101111011010");
/// ```
pub fn decompress(bytes: &[u8]) -> Vec<u8> {
    let mut output = Vec::with_capacity(bytes.len() * 8);

    for byte in bytes {
        output.extend_from_slice(format!("{:08b}", byte).as_bytes());
    }

    output
}

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

    const QUINE: &'static [u8; 66] =
        b"000101100100011010000000000001011011110010111100111111011111011010";

    const PRIMES: &'static [u8; 167] =
        b"00010001100110010100011010000000010110000010010001010111110111101001000110100001\
          11001101000000000010110111001110011111110111100000000111110011011100000010110000\
          0110110";

    const BLC: &'static [u8; 232] =
        b"01010001101000000001010110000000000111100001011111100111100001011100111100000011\
          11000010110110111001111100001111100001011110100111010010110011100001101100001011\
          111000011111000011100110111101111100111101110110000110010001101000011010";

    #[test]
    fn variables() {
        assert_eq!(from_binary(b"10"),   Ok(Var(1)));
        assert_eq!(from_binary(b"110"),  Ok(Var(2)));
        assert_eq!(from_binary(b"1110"), Ok(Var(3)));
    }

    #[test]
    fn abstractions() {
        assert_eq!(from_binary(b"0010"),     Ok(abs(Var(1))));
        assert_eq!(from_binary(b"000010"),   Ok(abs(abs(Var(1)))));
        assert_eq!(from_binary(b"00000010"), Ok(abs(abs(abs((Var(1)))))));
    }

    #[test]
    fn applications() {
        assert_eq!(from_binary(b"011010"),  Ok(app(Var(1), Var(1))));
        assert_eq!(from_binary(b"0110110"), Ok(app(Var(1), Var(2))));
        assert_eq!(from_binary(b"0111010"), Ok(app(Var(2), Var(1))));
    }

    #[test]
    fn ignoring_whitespaces() {
        assert_eq!(from_binary(b"00 00\t00\n10\r\n"), Ok(abs(abs(abs((Var(1)))))));
    }

    #[test]
    fn from_binary_and_back() {
        let k =    b"0000110";
        let v15 =  b"1111111111111110";
        let s =    b"00000001011110100111010";
        let succ = b"000000011100101111011010";

        assert_eq!(to_binary(&from_binary(&*k).unwrap()),      k);
        assert_eq!(to_binary(&from_binary(&*v15).unwrap()),    v15);
        assert_eq!(to_binary(&from_binary(&*s).unwrap()),      s);
        assert_eq!(to_binary(&from_binary(&*succ).unwrap()),   succ);
        assert_eq!(to_binary(&from_binary(&*QUINE).unwrap()),  &QUINE[..]);
        assert_eq!(to_binary(&from_binary(&*PRIMES).unwrap()), Vec::from(&PRIMES[..]));
        assert_eq!(to_binary(&from_binary(&*BLC).unwrap()),    Vec::from(&BLC[..]));
    }

    #[test]
    fn compression() {
        let primes_c = compress(&PRIMES[..]);
        assert_eq!(primes_c.first().unwrap(), &0x11);
        assert_eq!(primes_c.last().unwrap(),  &0x6c);

        let blc_c = compress(&BLC[..]);
        assert_eq!(blc_c.first().unwrap(), &0x51);
        assert_eq!(blc_c.last().unwrap(),  &0x1a);
    }

    #[test]
    fn decompression() {
        let s_c = vec![0x1, 0x7a, 0x74];
        assert_eq!(compress(&decompress(&s_c)), s_c);
    }

    #[test]
    fn compress_decompress() {
        assert_eq!(decompress(&compress(&BLC[..])), Vec::from(&BLC[..]));
    }
}
<commit_msg>follow some advice from clippy<commit_after>//! Binary encoding for lambda expressions

use lambda_calculus::term::*;
use self::Error::*;

/// An error that can occur if the input stream of "bits" is not valid binary lambda calculus.
#[derive(Debug, PartialEq)]
pub enum Error {
    NotATerm
}

/// Parse a binary-encoded lambda `Term`.
///
/// # Example
/// ```
/// use blc::binary_encoding::{from_binary, to_binary};
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(to_binary(&k.unwrap()), Vec::from(&b"0000110"[..]));
/// ```
pub fn from_binary(input: &[u8]) -> Result<Term, Error> {
    if let Some((result, _)) = _from_binary(input) {
        Ok(result)
    } else {
        Err(NotATerm)
    }
}

fn _from_binary(input: &[u8]) -> Option<(Term, &[u8])> {
    if input.is_empty() { return None }

    if [9, 10, 13, 32].contains(&input[0]) {
        _from_binary(&input[1..]) // skip whitespaces
    } else {
        match &input[0..2] {
            b"00" => {
                if let Some((term, rest)) = _from_binary(&input[2..]) {
                    Some((abs(term), rest))
                } else {
                    None
                }
            },
            b"01" => {
                if let Some((term1, rest1)) = _from_binary(&input[2..]) {
                    if let Some((term2, rest2)) = _from_binary(rest1) {
                        Some((app(term1, term2), rest2))
                    } else {
                        None
                    }
                } else {
                    None
                }
            },
            b"10" | b"11" => {
                let i = input.iter().take_while(|&b| *b == b'1').count();
                if input[2..].is_empty() {
                    Some((Var(i), &*b""))
                } else {
                    Some((Var(i), &input[i+1..]))
                }
            },
            _ => None
        }
    }
}

/// Represent a lambda `Term` in binary.
///
/// # Example
/// ```
/// use blc::binary_encoding::{from_binary, to_binary};
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(to_binary(&k.unwrap()), Vec::from(&b"0000110"[..]));
/// ```
pub fn to_binary(term: &Term) -> Vec<u8> {
    let mut output = Vec::new();
    _to_binary(term, &mut output);

    output
}

fn _to_binary(term: &Term, output: &mut Vec<u8>) {
    match *term {
        Var(i) => {
            for _ in 0..i { output.push(b'1') }
            output.push(b'0');
        }
        Abs(ref t) => {
            output.extend_from_slice(b"00");
            output.append(&mut to_binary(t));
        }
        App(ref t1, ref t2) => {
            output.extend_from_slice(b"01");
            output.append(&mut to_binary(t1));
            output.append(&mut to_binary(t2));
        }
    }
}

/// Convert a stream of "bits" into bytes. It is not always reversible with `decompress`, because
/// it produces full bytes, while the length of its input can be indivisible by 8.
///
/// # Example
/// ```
/// use blc::binary_encoding::{compress};
///
/// let succ_compressed = compress(&*b"000000011100101111011010");
/// assert_eq!(succ_compressed, vec![0x1, 0xCB, 0xDA]);
/// ```
pub fn compress(binary: &[u8]) -> Vec<u8> {
    let length = binary.len();
    let mut output = Vec::with_capacity(length / 8 + 1);
    let mut pos = 0;

    while pos <= length - 8 {
        output.push(bits_to_byte(&binary[pos..(pos + 8)]));
        pos += 8;
    }

    if pos != length {
        let mut last_byte = Vec::with_capacity(8);
        last_byte.extend_from_slice(&binary[pos..]);
        for _ in 0..(8 - (length - pos)) { last_byte.push(b'0') }
        output.push(bits_to_byte(&last_byte));
    }

    output
}

fn bits_to_byte(bits: &[u8]) -> u8 {
    bits.iter().fold(0, |acc, &b| acc * 2 + (b - 48))
}

/// Convert bytes into "bits" suitable for binary lambda calculus purposes.
///
/// # Example
/// ```
/// use blc::binary_encoding::{decompress};
///
/// let succ_compressed = vec![0x1, 0xCB, 0xDA];
/// assert_eq!(decompress(&succ_compressed), b"000000011100101111011010");
/// ```
pub fn decompress(bytes: &[u8]) -> Vec<u8> {
    let mut output = Vec::with_capacity(bytes.len() * 8);

    for byte in bytes {
        output.extend_from_slice(format!("{:08b}", byte).as_bytes());
    }

    output
}

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

    const QUINE: &'static [u8; 66] =
        b"000101100100011010000000000001011011110010111100111111011111011010";

    const PRIMES: &'static [u8; 167] =
        b"00010001100110010100011010000000010110000010010001010111110111101001000110100001\
          11001101000000000010110111001110011111110111100000000111110011011100000010110000\
          0110110";

    const BLC: &'static [u8; 232] =
        b"01010001101000000001010110000000000111100001011111100111100001011100111100000011\
          11000010110110111001111100001111100001011110100111010010110011100001101100001011\
          111000011111000011100110111101111100111101110110000110010001101000011010";

    #[test]
    fn variables() {
        assert_eq!(from_binary(b"10"),   Ok(Var(1)));
        assert_eq!(from_binary(b"110"),  Ok(Var(2)));
        assert_eq!(from_binary(b"1110"), Ok(Var(3)));
    }

    #[test]
    fn abstractions() {
        assert_eq!(from_binary(b"0010"),     Ok(abs(Var(1))));
        assert_eq!(from_binary(b"000010"),   Ok(abs(abs(Var(1)))));
        assert_eq!(from_binary(b"00000010"), Ok(abs(abs(abs((Var(1)))))));
    }

    #[test]
    fn applications() {
        assert_eq!(from_binary(b"011010"),  Ok(app(Var(1), Var(1))));
        assert_eq!(from_binary(b"0110110"), Ok(app(Var(1), Var(2))));
        assert_eq!(from_binary(b"0111010"), Ok(app(Var(2), Var(1))));
    }

    #[test]
    fn ignoring_whitespaces() {
        assert_eq!(from_binary(b"00 00\t00\n10\r\n"), Ok(abs(abs(abs((Var(1)))))));
    }

    #[test]
    fn from_binary_and_back() {
        let k =    b"0000110";
        let v15 =  b"1111111111111110";
        let s =    b"00000001011110100111010";
        let succ = b"000000011100101111011010";

        assert_eq!(to_binary(&from_binary(&*k).unwrap()),      k);
        assert_eq!(to_binary(&from_binary(&*v15).unwrap()),    v15);
        assert_eq!(to_binary(&from_binary(&*s).unwrap()),      s);
        assert_eq!(to_binary(&from_binary(&*succ).unwrap()),   succ);
        assert_eq!(to_binary(&from_binary(&*QUINE).unwrap()),  &QUINE[..]);
        assert_eq!(to_binary(&from_binary(&*PRIMES).unwrap()), Vec::from(&PRIMES[..]));
        assert_eq!(to_binary(&from_binary(&*BLC).unwrap()),    Vec::from(&BLC[..]));
    }

    #[test]
    fn compression() {
        let primes_c = compress(&PRIMES[..]);
        assert_eq!(primes_c.first().unwrap(), &0x11);
        assert_eq!(primes_c.last().unwrap(),  &0x6c);

        let blc_c = compress(&BLC[..]);
        assert_eq!(blc_c.first().unwrap(), &0x51);
        assert_eq!(blc_c.last().unwrap(),  &0x1a);
    }

    #[test]
    fn decompression() {
        let s_c = vec![0x1, 0x7a, 0x74];
        assert_eq!(compress(&decompress(&s_c)), s_c);
    }

    #[test]
    fn compress_decompress() {
        assert_eq!(decompress(&compress(&BLC[..])), Vec::from(&BLC[..]));
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc::channel;
use std::str::from_utf8;

use rustc_serialize::*;

use websocket::Message;
use websocket::Sender as WebSocketSender;
use websocket::Receiver as WebSocketReceiver;
use websocket::message::Type;

use payment_detection::PaymentDetection;

#[derive(RustcDecodable)]
pub struct AddressEvent {
	pub op: String,
	pub x: Transaction,
}

#[derive(RustcDecodable)]
pub struct Transaction {
	pub hash: String,
	pub ver: u8,
	pub vin_sz: u8,
	pub vout_sz: u8,
	pub lock_time: u64,
	pub size: u64,
	pub relayed_by: String,
	pub tx_index: u64,
	pub time: u64,
	pub inputs: Vec<TransactionInput>,
	pub out: Vec<TransactionOutput>
}

#[derive(RustcDecodable)]
pub struct TransactionOutput {
	pub value: u64,
	//pub type_: u8, too lazy to write a custom decoder just because "type" appears to be a rust keyword
	pub addr: String,
	pub tx_index: u64,
	pub spent: bool,
	pub n: u32,
	pub script: String,
}

#[derive(RustcDecodable)]
pub struct TransactionInput {
	pub prev_out: TransactionOutput,
	pub sequence: u64,
	pub script: String
}

#[derive(RustcEncodable)]
pub struct AddressSubscription<'a> {
	op: &'a str,
	addr: &'a str
}

const ADDRESS_SUBCRIPTION_OP: &'static str = "addr_sub";

impl<'a> AddressSubscription<'a> {
	pub fn new(address: &str) -> AddressSubscription {
		AddressSubscription {
			op: ADDRESS_SUBCRIPTION_OP,
			addr: address
		}
	}
}

pub struct BlockchainInfo<'a> {
	websocket_url: String,
	websocket_msg: String,
	address: &'a str,
	amount: u64
}

const WEBSOCKET_URL: &'static str = "wss://ws.blockchain.info/inv";

enum PaymentError {
	InsufficientAmount,
	Timeout,
	InvalidJsonResponse,
	WebSocketError
}

impl<'a> PaymentDetection<'a> for BlockchainInfo<'a> {
	fn new(address: &'a str, amount: u64) -> Self {
		let address_subscription = AddressSubscription::new(address);
		let json_request = json::encode(&address_subscription).unwrap();

		BlockchainInfo {
			websocket_url: WEBSOCKET_URL.to_string(),
			websocket_msg: json_request,
			address: &address,
			amount: amount
		}
	}

	fn wait(&self) -> Result<(), &'static str> {
		use std::thread;

		use websocket::Client;
		use websocket::client::request::Url;

		let websocket_url = Url::parse(&self.websocket_url).unwrap();
		println!("Connecting to {}", websocket_url);

		let request = Client::connect(websocket_url).unwrap();

		let response = request.send().unwrap(); // Send the request and retrieve a response

		println!("Validating response...");

		response.validate().unwrap(); // Validate the response

		println!("Successfully connected");

		let (mut ws_sender, mut ws_receiver) = response.begin().split();

		let (tx, rx) = channel();

		let tx_1 = tx.clone();

		let send_loop = thread::spawn(move || {
			loop {
				let message: Message = match rx.recv() {
					Ok(m) => m,
					Err(e) => {
						println!("Send Loop: {:?}", e);
						return Err(PaymentError::InvalidJsonResponse);
					}
				};

				match message.opcode {
					Type::Close => {
						let _ = ws_sender.send_message(&message);
						// If it's a close message, just send it and then return.
						return Ok(());
					}
					_ => (),
				}

				match ws_sender.send_message(&message) {
					Ok(()) => (),
					Err(e) => {
						println!("Send Loop: {:?}", e);
						let _ = ws_sender.send_message(&Message::close());
						return Err(PaymentError::WebSocketError);
					}
				}
			}
		});

		let address = self.address.to_string();
		let amount = self.amount.clone();
		let websocket_msg = self.websocket_msg.to_string().clone();

		let receive_loop = thread::spawn(move || {
			let mut amount_payed = 0;

			for message in ws_receiver.incoming_messages() {
				let message: Message = match message {
					Ok(m) => m,
					Err(e) => {
						println!("Receive Loop: {:?}", e);
						let _ = tx.send(Message::close());
						return;
						//return Err(PaymentError::WebSocketError);
					}
				};

				match message.opcode {
					Type::Close => {
						// Got a close message, so send a close message and return
						let _ = tx.send(Message::close());
						return;
						//return Err(PaymentError::Timeout);
					}

					Type::Text => {
						let data = from_utf8(&*message.payload);

						let data = match data {
					        Ok(v) => v,
					        Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
					    };

						let address_event: AddressEvent = match json::decode(&data) {
							Ok(ae) => ae,
							Err(e) => {
								println!("JSON Decoder: {}", e);
								return;
								//return Err(PaymentError::InvalidJsonResponse)
							}
						};

						let transaction: Transaction = address_event.x;

						for output in &transaction.out {
							if output.addr == address {
								println!("received {} satoshis from {}", output.value, &transaction.inputs[0].prev_out.addr);
								amount_payed = amount_payed + output.value;
							}
						}

						if amount_payed >= amount {
							println!("payment complete. exiting...");
							let _ = tx.send(Message::close());
							return;
							//return Ok(());
						} else {
							return;
							//return Err(PaymentError::InsufficientAmount);
						}
					}

					_ => {
						println!("Receive Loop: unhandled websocket message: {:?}", message);
						return;
						//return Err(PaymentError::InvalidJsonResponse);
					}
				}
			}
		});

		let _ = tx_1.send(Message::text(websocket_msg));

		println!("Waiting for child threads to exit");

		let _ = send_loop.join();
		println!("send loop finished");

		let r_result = receive_loop.join();
		println!("receive loop finished");

		match r_result {
			Ok(_) => Ok(()),
			Err(_) => Err("receive loop error {}")
		}
	}
}

<commit_msg>temporary fix for correct distinction between payment success/failure<commit_after>use std::sync::mpsc::channel;
use std::str::from_utf8;

use rustc_serialize::*;

use websocket::Message;
use websocket::Sender as WebSocketSender;
use websocket::Receiver as WebSocketReceiver;
use websocket::message::Type;

use payment_detection::PaymentDetection;

#[derive(RustcDecodable)]
pub struct AddressEvent {
	pub op: String,
	pub x: Transaction,
}

#[derive(RustcDecodable)]
pub struct Transaction {
	pub hash: String,
	pub ver: u8,
	pub vin_sz: u8,
	pub vout_sz: u8,
	pub lock_time: u64,
	pub size: u64,
	pub relayed_by: String,
	pub tx_index: u64,
	pub time: u64,
	pub inputs: Vec<TransactionInput>,
	pub out: Vec<TransactionOutput>
}

#[derive(RustcDecodable)]
pub struct TransactionOutput {
	pub value: u64,
	//pub type_: u8, too lazy to write a custom decoder just because "type" appears to be a rust keyword
	pub addr: String,
	pub tx_index: u64,
	pub spent: bool,
	pub n: u32,
	pub script: String,
}

#[derive(RustcDecodable)]
pub struct TransactionInput {
	pub prev_out: TransactionOutput,
	pub sequence: u64,
	pub script: String
}

#[derive(RustcEncodable)]
pub struct AddressSubscription<'a> {
	op: &'a str,
	addr: &'a str
}

const ADDRESS_SUBCRIPTION_OP: &'static str = "addr_sub";

impl<'a> AddressSubscription<'a> {
	pub fn new(address: &str) -> AddressSubscription {
		AddressSubscription {
			op: ADDRESS_SUBCRIPTION_OP,
			addr: address
		}
	}
}

pub struct BlockchainInfo<'a> {
	websocket_url: String,
	websocket_msg: String,
	address: &'a str,
	amount: u64
}

const WEBSOCKET_URL: &'static str = "wss://ws.blockchain.info/inv";

enum PaymentError {
	InsufficientAmount,
	Timeout,
	InvalidJsonResponse,
	WebSocketError
}

impl<'a> PaymentDetection<'a> for BlockchainInfo<'a> {
	fn new(address: &'a str, amount: u64) -> Self {
		let address_subscription = AddressSubscription::new(address);
		let json_request = json::encode(&address_subscription).unwrap();

		BlockchainInfo {
			websocket_url: WEBSOCKET_URL.to_string(),
			websocket_msg: json_request,
			address: &address,
			amount: amount
		}
	}

	fn wait(&self) -> Result<(), &'static str> {
		use std::thread;

		use websocket::Client;
		use websocket::client::request::Url;

		let websocket_url = Url::parse(&self.websocket_url).unwrap();
		println!("Connecting to {}", websocket_url);

		let request = Client::connect(websocket_url).unwrap();

		let response = request.send().unwrap(); // Send the request and retrieve a response

		println!("Validating response...");

		response.validate().unwrap(); // Validate the response

		println!("Successfully connected");

		let (mut ws_sender, mut ws_receiver) = response.begin().split();

		let (tx, rx) = channel();

		let tx_1 = tx.clone();

		let send_loop = thread::spawn(move || {
			loop {
				let message: Message = match rx.recv() {
					Ok(m) => m,
					Err(e) => {
						println!("Send Loop: {:?}", e);
						return Err(PaymentError::InvalidJsonResponse);
					}
				};

				match message.opcode {
					Type::Close => {
						let _ = ws_sender.send_message(&message);
						// If it's a close message, just send it and then return.
						return Ok(());
					}
					_ => (),
				}

				match ws_sender.send_message(&message) {
					Ok(()) => (),
					Err(e) => {
						println!("Send Loop: {:?}", e);
						let _ = ws_sender.send_message(&Message::close());
						return Err(PaymentError::WebSocketError);
					}
				}
			}
		});

		let address = self.address.to_string();
		let amount = self.amount.clone();
		let websocket_msg = self.websocket_msg.to_string().clone();

		let receive_loop = thread::spawn(move || {
			let mut amount_payed = 0;

			for message in ws_receiver.incoming_messages() {
				let message: Message = match message {
					Ok(m) => m,
					Err(e) => {
						println!("Receive Loop: {:?}", e);
						let _ = tx.send(Message::close());
						panic!("Err(PaymentError::WebSocketError)")
					}
				};

				match message.opcode {
					Type::Close => {
						// Got a close message, so send a close message and return
						let _ = tx.send(Message::close());
					}

					Type::Text => {
						let data = from_utf8(&*message.payload);

						let data = match data {
					        Ok(v) => v,
					        Err(e) => panic!("Invalid UTF-8 sequence: {}", e)
					    };

						let address_event: AddressEvent = match json::decode(&data) {
							Ok(ae) => ae,
							Err(e) => {
								println!("JSON Decoder: {}", e);
								panic!("Err(PaymentError::InvalidJsonResponse)");
							}
						};

						let transaction: Transaction = address_event.x;

						for output in &transaction.out {
							if output.addr == address {
								println!("received {} satoshis from {}", output.value, &transaction.inputs[0].prev_out.addr);
								amount_payed = amount_payed + output.value;
							}
						}

						if amount_payed >= amount {
							println!("payment complete. exiting...");
							let _ = tx.send(Message::close());
							return;
						} else {
							panic!("Err(PaymentError::InsufficientAmount)");
						}
					}

					_ => {
						println!("Receive Loop: unhandled websocket message: {:?}", message);
						panic!("Err(PaymentError::InvalidJsonResponse)");
					}
				}
			}
		});

		let _ = tx_1.send(Message::text(websocket_msg));

		println!("Waiting for child threads to exit");

		let _ = send_loop.join();
		println!("send loop finished");

		let r_result = receive_loop.join();
		println!("receive loop finished");

		match r_result {
			Ok(_) => Ok(()),
			Err(_) => Err("receive loop error {}")
		}
	}
}

<|endoftext|>


<commit_before>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#[desc = "A fast Bloom filter implementation."];
#[license = "BSD"];
#[crate_id="bloomfilter#0.1"];
#[crate_type = "rlib"];
#[warn(non_camel_case_types, non_uppercase_statics, non_uppercase_statics, unnecessary_qualification, managed_heap_memory)];

extern crate collections;
extern crate extra;

use std::cmp;
use std::hash::Hash;
use std::num;
use std::rand;
use std::hash::sip::SipHasher;
use std::hash::Hasher;
use collections::bitv;

#[cfg(test)]
use std::rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    priv bitmap: bitv::Bitv,
    priv bitmap_bits: u64,
    priv k_num: uint,
    priv sips: [SipHasher, ..2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: uint, items_count: uint) -> Bloom {
        assert!(bitmap_size > 0u && items_count > 0u);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::new(bitmap_bits as uint, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: uint, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: uint, fp_p: f64) -> uint {
        assert!(items_count > 0u);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = num::ln(2.0f64);
        let log2_2 = log2 * log2;
        ((items_count as f64) * num::ln(fp_p) / (-8.0 * log2_2)).ceil() as uint
    }

/// Record the presence of an item.
    pub fn set<T: Hash>(& mut self, item: T) {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T: Hash>(&self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T: Hash>(&mut self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: uint) -> uint {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * num::ln(2.0f64).ceil()) as uint;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T: Hash>(&self, hashes: & mut [u64, ..2],
                  item: &T, k_i: uint) -> u64 {
        if k_i < 2 {
            let sip = self.sips[k_i];
            let hash = sip.hash(item);
            hashes[k_i] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::task_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<commit_msg>rand is now in its own crate<commit_after>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#[desc = "A fast Bloom filter implementation."];
#[license = "BSD"];
#[crate_id="bloomfilter#0.1"];
#[crate_type = "rlib"];
#[warn(non_camel_case_types, non_uppercase_statics, non_uppercase_statics, unnecessary_qualification, managed_heap_memory)];

extern crate collections;
extern crate extra;
extern crate rand;

use std::cmp;
use std::hash::Hash;
use std::num;
use std::hash::sip::SipHasher;
use std::hash::Hasher;
use collections::bitv;

#[cfg(test)]
use std::rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    priv bitmap: bitv::Bitv,
    priv bitmap_bits: u64,
    priv k_num: uint,
    priv sips: [SipHasher, ..2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: uint, items_count: uint) -> Bloom {
        assert!(bitmap_size > 0u && items_count > 0u);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::new(bitmap_bits as uint, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: uint, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: uint, fp_p: f64) -> uint {
        assert!(items_count > 0u);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = num::ln(2.0f64);
        let log2_2 = log2 * log2;
        ((items_count as f64) * num::ln(fp_p) / (-8.0 * log2_2)).ceil() as uint
    }

/// Record the presence of an item.
    pub fn set<T: Hash>(& mut self, item: T) {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T: Hash>(&self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T: Hash>(&mut self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: uint) -> uint {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * num::ln(2.0f64).ceil()) as uint;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T: Hash>(&self, hashes: & mut [u64, ..2],
                  item: &T, k_i: uint) -> u64 {
        if k_i < 2 {
            let sip = self.sips[k_i];
            let hash = sip.hash(item);
            hashes[k_i] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::task_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs;
use std::fs::{canonicalize, read_dir};
use std::path::{Path, PathBuf};

use language_tags::LanguageTag;

use layout::Layout;
use project::Project;
use serde_yaml::Value;
use target::Target;

pub mod layout;
mod project;
mod target;

const PROJECT_FILENAME: &str = "project.yaml";
const LAYOUTS_FOLDER: &str = "layouts";
const TARGETS_FOLDER: &str = "targets";

const YAML_EXT: &str = "yaml";

pub const DEFAULT_DECIMAL: &str = ".";
const COMMA_DECIMAL: &str = ",";

#[derive(Debug)]
pub struct KbdgenBundle {
    pub path: PathBuf,
    pub project: Project,
    pub layouts: HashMap<LanguageTag, Layout>,
    pub targets: Vec<Target>,
}

pub fn read_kbdgen_bundle(path: &Path) -> Result<KbdgenBundle, Error> {
    let canonical_bundle_path: PathBuf = canonicalize(path)?;

    tracing::info!("Canonical Bundle Path: {:?}", &canonical_bundle_path);

    let project: Project = serde_yaml::from_str(&fs::read_to_string(
        canonical_bundle_path.join(PROJECT_FILENAME),
    )?)?;

    let layouts_path = canonical_bundle_path.join(LAYOUTS_FOLDER);
    let targets_path = canonical_bundle_path.join(TARGETS_FOLDER);

    let layouts = read_layouts(&layouts_path)?;
    let targets = read_targets(&targets_path)?;

    Ok(KbdgenBundle {
        path: canonical_bundle_path,
        project,
        layouts,
        targets,
    })
}

fn read_layouts(path: &Path) -> Result<HashMap<LanguageTag, Layout>, Error> {
    read_dir(path)?
        .filter_map(Result::ok)
        .map(|file| file.path())
        .filter(|path| path.is_file())
        .filter(|path| match path.extension() {
            Some(ext) => ext == YAML_EXT,
            None => false,
        })
        .map(|path| {
            let tag = path
                .file_stem()
                .ok_or_else(|| Error::NoFileStem { path: path.clone() })?
                .to_string_lossy();

            let tag: LanguageTag = tag.parse().map_err(|_| Error::InvalidLanguageTag {
                tag: tag.to_string(),
            })?;

            let mut yaml: Value = serde_yaml::from_str(&fs::read_to_string(path)?)?;
            yaml.as_mapping_mut()
                .expect("top level yaml type must be a mapping")
                .insert(
                    Value::String("languageTag".to_owned()),
                    Value::String(tag.to_string()),
                );

            let mut layout: Layout = serde_yaml::from_value(yaml)?;

            let _autonym = layout
                .display_names
                .get(&tag.primary_language().to_owned())
                .unwrap_or_else(|| {
                    panic!("displayNames for the layout do not have the autonym");
                });

            if let Some(decimal) = layout.decimal.as_ref() {
                if decimal != COMMA_DECIMAL && decimal != DEFAULT_DECIMAL {
                    tracing::error!(
                        "{} is not supported as a decimal character, setting to {}",
                        decimal,
                        DEFAULT_DECIMAL
                    );
                    layout.decimal = Some(DEFAULT_DECIMAL.to_owned());
                }
            };

            Ok((tag, layout))
        })
        .collect()
}

fn read_targets(path: &Path) -> Result<Vec<Target>, Error> {
    read_dir(path)?
        .filter_map(Result::ok)
        .map(|file| file.path())
        .filter(|path| path.is_file())
        .filter(|path| match path.extension() {
            Some(ext) => ext == YAML_EXT,
            None => false,
        })
        .map(|path| {
            let target_name = path
                .file_stem()
                .ok_or_else(|| Error::NoFileStem { path: path.clone() })?
                .to_string_lossy();

            let target: Target = match target_name.as_ref() {
                "windows" => {
                    let win_target = serde_yaml::from_str(&fs::read_to_string(path)?)?;
                    Target::Windows(win_target)
                }
                "ios" => {
                    #[allow(non_snake_case)]
                    let iOS_target = serde_yaml::from_str(&fs::read_to_string(path)?)?;
                    Target::iOS(iOS_target)
                }
                _ => {
                    todo!()
                }
            };

            Ok(target)
        })
        .collect()
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("{0}")]
    IoError(#[from] std::io::Error),

    #[error("{0}")]
    YamlError(#[from] serde_yaml::Error),

    #[error(".yaml files must have a stem, failed to parse: `{}`", path.display())]
    NoFileStem { path: PathBuf },

    #[error("Failed to parse language tag: `{}`", tag)]
    InvalidLanguageTag { tag: String },
}
<commit_msg>Make target yaml file loading more tolerant<commit_after>use std::collections::HashMap;
use std::fs;
use std::fs::{canonicalize, read_dir};
use std::path::{Path, PathBuf};

use language_tags::LanguageTag;

use layout::Layout;
use project::Project;
use serde_yaml::Value;
use target::Target;

pub mod layout;
mod project;
mod target;

const PROJECT_FILENAME: &str = "project.yaml";
const LAYOUTS_FOLDER: &str = "layouts";
const TARGETS_FOLDER: &str = "targets";

const YAML_EXT: &str = "yaml";

pub const DEFAULT_DECIMAL: &str = ".";
const COMMA_DECIMAL: &str = ",";

#[derive(Debug)]
pub struct KbdgenBundle {
    pub path: PathBuf,
    pub project: Project,
    pub layouts: HashMap<LanguageTag, Layout>,
    pub targets: Vec<Target>,
}

pub fn read_kbdgen_bundle(path: &Path) -> Result<KbdgenBundle, Error> {
    let canonical_bundle_path: PathBuf = canonicalize(path)?;

    tracing::info!("Canonical Bundle Path: {:?}", &canonical_bundle_path);

    let project: Project = serde_yaml::from_str(&fs::read_to_string(
        canonical_bundle_path.join(PROJECT_FILENAME),
    )?)?;

    let layouts_path = canonical_bundle_path.join(LAYOUTS_FOLDER);
    let targets_path = canonical_bundle_path.join(TARGETS_FOLDER);

    let layouts = read_layouts(&layouts_path)?;
    let targets = read_targets(&targets_path)?;

    Ok(KbdgenBundle {
        path: canonical_bundle_path,
        project,
        layouts,
        targets,
    })
}

fn read_layouts(path: &Path) -> Result<HashMap<LanguageTag, Layout>, Error> {
    read_dir(path)?
        .filter_map(Result::ok)
        .map(|file| file.path())
        .filter(|path| path.is_file())
        .filter(|path| match path.extension() {
            Some(ext) => ext == YAML_EXT,
            None => false,
        })
        .map(|path| {
            let tag = path
                .file_stem()
                .ok_or_else(|| Error::NoFileStem { path: path.clone() })?
                .to_string_lossy();

            let tag: LanguageTag = tag.parse().map_err(|_| Error::InvalidLanguageTag {
                tag: tag.to_string(),
            })?;

            let mut yaml: Value = serde_yaml::from_str(&fs::read_to_string(path)?)?;
            yaml.as_mapping_mut()
                .expect("top level yaml type must be a mapping")
                .insert(
                    Value::String("languageTag".to_owned()),
                    Value::String(tag.to_string()),
                );

            let mut layout: Layout = serde_yaml::from_value(yaml)?;

            let _autonym = layout
                .display_names
                .get(&tag.primary_language().to_owned())
                .unwrap_or_else(|| {
                    panic!("displayNames for the layout do not have the autonym");
                });

            if let Some(decimal) = layout.decimal.as_ref() {
                if decimal != COMMA_DECIMAL && decimal != DEFAULT_DECIMAL {
                    tracing::error!(
                        "{} is not supported as a decimal character, setting to {}",
                        decimal,
                        DEFAULT_DECIMAL
                    );
                    layout.decimal = Some(DEFAULT_DECIMAL.to_owned());
                }
            };

            Ok((tag, layout))
        })
        .collect()
}

fn load_yaml<T>(path: &Path) -> Option<T>
where
    T: for<'de> serde::Deserialize<'de>,
{
    let s = match fs::read_to_string(path) {
        Ok(v) => v,
        Err(e) => {
            tracing::error!(error = ?e, "Failed to read file to string");
            return None;
        }
    };

    match serde_yaml::from_str::<T>(&s) {
        Ok(v) => Some(v),
        Err(e) => {
            tracing::error!(error = ?e, "Error parsing YAML");
            None
        }
    }
}

fn read_targets(path: &Path) -> Result<Vec<Target>, Error> {
    Ok(read_dir(path)?
        .filter_map(Result::ok)
        .map(|file| file.path())
        .filter(|path| path.is_file())
        .filter(|path| match path.extension() {
            Some(ext) => ext == YAML_EXT,
            None => false,
        })
        .filter_map(|path| {
            let target_name = path
                .file_stem()
                .ok_or_else(|| Error::NoFileStem { path: path.clone() })
                .map(|x| x.to_string_lossy())
                .ok()?;

            let target: Target = match target_name.as_ref() {
                "windows" => {
                    let win_target = load_yaml(&path)?;
                    Target::Windows(win_target)
                }
                "ios" => {
                    let ios_target = load_yaml(&path)?;
                    Target::iOS(ios_target)
                }
                "macos" => {
                    let macos_target = load_yaml(&path)?;
                    Target::MacOS(macos_target)
                }
                name => {
                    tracing::warn!("Saw target with name {name} but did not parse");
                    return None;
                }
            };

            Some(target)
        })
        .collect())
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("{0}")]
    IoError(#[from] std::io::Error),

    #[error("{0}")]
    YamlError(#[from] serde_yaml::Error),

    #[error(".yaml files must have a stem, failed to parse: `{}`", path.display())]
    NoFileStem { path: PathBuf },

    #[error("Failed to parse language tag: `{}`", tag)]
    InvalidLanguageTag { tag: String },
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Command-line interface of the rustbuild build system.
//!
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;

use getopts::Options;

use Build;
use config::Config;
use metadata;
use step;

/// Deserialized version of all flags for this compile.
pub struct Flags {
    pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
    pub on_fail: Option<String>,
    pub stage: Option<u32>,
    pub keep_stage: Option<u32>,
    pub build: String,
    pub host: Vec<String>,
    pub target: Vec<String>,
    pub config: Option<PathBuf>,
    pub src: Option<PathBuf>,
    pub jobs: Option<u32>,
    pub cmd: Subcommand,
    pub incremental: bool,
}

impl Flags {
    pub fn verbose(&self) -> bool {
        self.verbose > 0
    }

    pub fn very_verbose(&self) -> bool {
        self.verbose > 1
    }
}

pub enum Subcommand {
    Build {
        paths: Vec<PathBuf>,
    },
    Doc {
        paths: Vec<PathBuf>,
    },
    Test {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
        no_fail_fast: bool,
    },
    Bench {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Clean,
    Dist {
        paths: Vec<PathBuf>,
    },
    Install {
        paths: Vec<PathBuf>,
    },
}

impl Flags {
    pub fn parse(args: &[String]) -> Flags {
        let mut extra_help = String::new();
        let mut subcommand_help = format!("\
Usage: x.py <subcommand> [options] [<paths>...]

Subcommands:
    build       Compile either the compiler or libraries
    test        Build and run some test suites
    bench       Build and run some benchmarks
    doc         Build documentation
    clean       Clean out build directories
    dist        Build distribution artifacts
    install     Install distribution artifacts

To learn more about a subcommand, run `./x.py <subcommand> -h`");

        let mut opts = Options::new();
        // Options common to all subcommands
        opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
        opts.optflag("i", "incremental", "use incremental compilation");
        opts.optopt("", "config", "TOML configuration file for build", "FILE");
        opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
        opts.optmulti("", "host", "host targets to build", "HOST");
        opts.optmulti("", "target", "target targets to build", "TARGET");
        opts.optopt("", "on-fail", "command to run on failure", "CMD");
        opts.optopt("", "stage", "stage to build", "N");
        opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
        opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
        opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
        opts.optflag("h", "help", "print this help message");

        // fn usage()
        let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
            println!("{}", opts.usage(subcommand_help));
            if !extra_help.is_empty() {
                println!("{}", extra_help);
            }
            process::exit(exit_code);
        };

        // We can't use getopt to parse the options until we have completed specifying which
        // options are valid, but under the current implementation, some options are conditional on
        // the subcommand. Therefore we must manually identify the subcommand first, so that we can
        // complete the definition of the options.  Then we can use the getopt::Matches object from
        // there on out.
        let mut possible_subcommands = args.iter().collect::<Vec<_>>();
        possible_subcommands.retain(|&s|
                                           (s == "build")
                                        || (s == "test")
                                        || (s == "bench")
                                        || (s == "doc")
                                        || (s == "clean")
                                        || (s == "dist")
                                        || (s == "install"));
        let subcommand = match possible_subcommands.first() {
            Some(s) => s,
            None => {
                // No subcommand -- show the general usage and subcommand help
                println!("{}\n", subcommand_help);
                process::exit(0);
            }
        };

        // Some subcommands get extra options
        match subcommand.as_str() {
            "test"  => {
                opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
            },
            "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
            _ => { },
        };

        // Done specifying what options are possible, so do the getopts parsing
        let matches = opts.parse(&args[..]).unwrap_or_else(|e| {
            // Invalid argument/option format
            println!("\n{}\n", e);
            usage(1, &opts, &subcommand_help, &extra_help);
        });
        // Extra sanity check to make sure we didn't hit this crazy corner case:
        //
        //     ./x.py --frobulate clean build
        //            ^-- option  ^     ^- actual subcommand
        //                        \_ arg to option could be mistaken as subcommand
        let mut pass_sanity_check = true;
        match matches.free.get(0) {
            Some(check_subcommand) => {
                if &check_subcommand != subcommand {
                    pass_sanity_check = false;
                }
            },
            None => {
                pass_sanity_check = false;
            }
        }
        if !pass_sanity_check {
            println!("{}\n", subcommand_help);
            println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
                      You may need to move some options to after the subcommand.\n");
            process::exit(1);
        }
        // Extra help text for some commands
        match subcommand.as_str() {
            "build" => {
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories to the crates
    and/or artifacts to compile. For example:

        ./x.py build src/libcore
        ./x.py build src/libcore src/libproc_macro
        ./x.py build src/libstd --stage 1

    If no arguments are passed then the complete artifacts for that stage are
    also compiled.

        ./x.py build
        ./x.py build --stage 1

    For a quick build of a usable compiler, you can pass:

        ./x.py build --stage 1 src/libtest

    This will first build everything once (like --stage 0 without further
    arguments would), and then use the compiler built in stage 0 to build
    src/libtest and its dependencies.
    Once this is done, build/$ARCH/stage1 contains a usable compiler.");
            }
            "test" => {
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories to tests that
    should be compiled and run. For example:

        ./x.py test src/test/run-pass
        ./x.py test src/libstd --test-args hash_map
        ./x.py test src/libstd --stage 0

    If no arguments are passed then the complete artifacts for that stage are
    compiled and tested.

        ./x.py test
        ./x.py test --stage 1");
            }
            "doc" => {
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories of documentation
    to build. For example:

        ./x.py doc src/doc/book
        ./x.py doc src/doc/nomicon
        ./x.py doc src/doc/book src/libstd

    If no arguments are passed then everything is documented:

        ./x.py doc
        ./x.py doc --stage 1");
            }
            _ => { }
        };
        // Get any optional paths which occur after the subcommand
        let cwd = t!(env::current_dir());
        let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::<Vec<_>>();

        // All subcommands can have an optional "Available paths" section
        if matches.opt_present("verbose") {
            let flags = Flags::parse(&["build".to_string()]);
            let mut config = Config::default();
            config.build = flags.build.clone();
            let mut build = Build::new(flags, config);
            metadata::build(&mut build);
            let maybe_rules_help = step::build_rules(&build).get_help(subcommand);
            if maybe_rules_help.is_some() {
                extra_help.push_str(maybe_rules_help.unwrap().as_str());
            }
        } else {
            extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.",
                     subcommand).as_str());
        }

        // User passed in -h/--help?
        if matches.opt_present("help") {
            usage(0, &opts, &subcommand_help, &extra_help);
        }

        let cmd = match subcommand.as_str() {
            "build" => {
                Subcommand::Build { paths: paths }
            }
            "test" => {
                Subcommand::Test {
                    paths: paths,
                    test_args: matches.opt_strs("test-args"),
                    no_fail_fast: matches.opt_present("no-fail-fast"),
                }
            }
            "bench" => {
                Subcommand::Bench {
                    paths: paths,
                    test_args: matches.opt_strs("test-args"),
                }
            }
            "doc" => {
                Subcommand::Doc { paths: paths }
            }
            "clean" => {
                if paths.len() > 0 {
                    println!("\nclean takes no arguments\n");
                    usage(1, &opts, &subcommand_help, &extra_help);
                }
                Subcommand::Clean
            }
            "dist" => {
                Subcommand::Dist {
                    paths: paths,
                }
            }
            "install" => {
                Subcommand::Install {
                    paths: paths,
                }
            }
            _ => {
                usage(1, &opts, &subcommand_help, &extra_help);
            }
        };

        let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
            if fs::metadata("config.toml").is_ok() {
                Some(PathBuf::from("config.toml"))
            } else {
                None
            }
        });

        let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap());

        if matches.opt_present("incremental") {
            if stage.is_none() {
                stage = Some(1);
            }
        }

        Flags {
            verbose: matches.opt_count("verbose"),
            stage: stage,
            on_fail: matches.opt_str("on-fail"),
            keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
            build: matches.opt_str("build").unwrap_or_else(|| {
                env::var("BUILD").unwrap()
            }),
            host: split(matches.opt_strs("host")),
            target: split(matches.opt_strs("target")),
            config: cfg_file,
            src: matches.opt_str("src").map(PathBuf::from),
            jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
            cmd: cmd,
            incremental: matches.opt_present("incremental"),
        }
    }
}

impl Subcommand {
    pub fn test_args(&self) -> Vec<&str> {
        match *self {
            Subcommand::Test { ref test_args, .. } |
            Subcommand::Bench { ref test_args, .. } => {
                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
            }
            _ => Vec::new(),
        }
    }

    pub fn no_fail_fast(&self) -> bool {
        match *self {
            Subcommand::Test { no_fail_fast, .. } => no_fail_fast,
            _ => false,
        }
    }
}

fn split(s: Vec<String>) -> Vec<String> {
    s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
}
<commit_msg>Use custom cargo/rustc paths when parsing flags.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Command-line interface of the rustbuild build system.
//!
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;

use getopts::Options;

use Build;
use config::Config;
use metadata;
use step;

/// Deserialized version of all flags for this compile.
pub struct Flags {
    pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
    pub on_fail: Option<String>,
    pub stage: Option<u32>,
    pub keep_stage: Option<u32>,
    pub build: String,
    pub host: Vec<String>,
    pub target: Vec<String>,
    pub config: Option<PathBuf>,
    pub src: Option<PathBuf>,
    pub jobs: Option<u32>,
    pub cmd: Subcommand,
    pub incremental: bool,
}

impl Flags {
    pub fn verbose(&self) -> bool {
        self.verbose > 0
    }

    pub fn very_verbose(&self) -> bool {
        self.verbose > 1
    }
}

pub enum Subcommand {
    Build {
        paths: Vec<PathBuf>,
    },
    Doc {
        paths: Vec<PathBuf>,
    },
    Test {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
        no_fail_fast: bool,
    },
    Bench {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Clean,
    Dist {
        paths: Vec<PathBuf>,
    },
    Install {
        paths: Vec<PathBuf>,
    },
}

impl Flags {
    pub fn parse(args: &[String]) -> Flags {
        let mut extra_help = String::new();
        let mut subcommand_help = format!("\
Usage: x.py <subcommand> [options] [<paths>...]

Subcommands:
    build       Compile either the compiler or libraries
    test        Build and run some test suites
    bench       Build and run some benchmarks
    doc         Build documentation
    clean       Clean out build directories
    dist        Build distribution artifacts
    install     Install distribution artifacts

To learn more about a subcommand, run `./x.py <subcommand> -h`");

        let mut opts = Options::new();
        // Options common to all subcommands
        opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
        opts.optflag("i", "incremental", "use incremental compilation");
        opts.optopt("", "config", "TOML configuration file for build", "FILE");
        opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
        opts.optmulti("", "host", "host targets to build", "HOST");
        opts.optmulti("", "target", "target targets to build", "TARGET");
        opts.optopt("", "on-fail", "command to run on failure", "CMD");
        opts.optopt("", "stage", "stage to build", "N");
        opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
        opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
        opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
        opts.optflag("h", "help", "print this help message");

        // fn usage()
        let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
            println!("{}", opts.usage(subcommand_help));
            if !extra_help.is_empty() {
                println!("{}", extra_help);
            }
            process::exit(exit_code);
        };

        // We can't use getopt to parse the options until we have completed specifying which
        // options are valid, but under the current implementation, some options are conditional on
        // the subcommand. Therefore we must manually identify the subcommand first, so that we can
        // complete the definition of the options.  Then we can use the getopt::Matches object from
        // there on out.
        let mut possible_subcommands = args.iter().collect::<Vec<_>>();
        possible_subcommands.retain(|&s|
                                           (s == "build")
                                        || (s == "test")
                                        || (s == "bench")
                                        || (s == "doc")
                                        || (s == "clean")
                                        || (s == "dist")
                                        || (s == "install"));
        let subcommand = match possible_subcommands.first() {
            Some(s) => s,
            None => {
                // No subcommand -- show the general usage and subcommand help
                println!("{}\n", subcommand_help);
                process::exit(0);
            }
        };

        // Some subcommands get extra options
        match subcommand.as_str() {
            "test"  => {
                opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
            },
            "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
            _ => { },
        };

        // Done specifying what options are possible, so do the getopts parsing
        let matches = opts.parse(&args[..]).unwrap_or_else(|e| {
            // Invalid argument/option format
            println!("\n{}\n", e);
            usage(1, &opts, &subcommand_help, &extra_help);
        });
        // Extra sanity check to make sure we didn't hit this crazy corner case:
        //
        //     ./x.py --frobulate clean build
        //            ^-- option  ^     ^- actual subcommand
        //                        \_ arg to option could be mistaken as subcommand
        let mut pass_sanity_check = true;
        match matches.free.get(0) {
            Some(check_subcommand) => {
                if &check_subcommand != subcommand {
                    pass_sanity_check = false;
                }
            },
            None => {
                pass_sanity_check = false;
            }
        }
        if !pass_sanity_check {
            println!("{}\n", subcommand_help);
            println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
                      You may need to move some options to after the subcommand.\n");
            process::exit(1);
        }
        // Extra help text for some commands
        match subcommand.as_str() {
            "build" => {
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories to the crates
    and/or artifacts to compile. For example:

        ./x.py build src/libcore
        ./x.py build src/libcore src/libproc_macro
        ./x.py build src/libstd --stage 1

    If no arguments are passed then the complete artifacts for that stage are
    also compiled.

        ./x.py build
        ./x.py build --stage 1

    For a quick build of a usable compiler, you can pass:

        ./x.py build --stage 1 src/libtest

    This will first build everything once (like --stage 0 without further
    arguments would), and then use the compiler built in stage 0 to build
    src/libtest and its dependencies.
    Once this is done, build/$ARCH/stage1 contains a usable compiler.");
            }
            "test" => {
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories to tests that
    should be compiled and run. For example:

        ./x.py test src/test/run-pass
        ./x.py test src/libstd --test-args hash_map
        ./x.py test src/libstd --stage 0

    If no arguments are passed then the complete artifacts for that stage are
    compiled and tested.

        ./x.py test
        ./x.py test --stage 1");
            }
            "doc" => {
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories of documentation
    to build. For example:

        ./x.py doc src/doc/book
        ./x.py doc src/doc/nomicon
        ./x.py doc src/doc/book src/libstd

    If no arguments are passed then everything is documented:

        ./x.py doc
        ./x.py doc --stage 1");
            }
            _ => { }
        };
        // Get any optional paths which occur after the subcommand
        let cwd = t!(env::current_dir());
        let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::<Vec<_>>();

        let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
            if fs::metadata("config.toml").is_ok() {
                Some(PathBuf::from("config.toml"))
            } else {
                None
            }
        });

        // All subcommands can have an optional "Available paths" section
        if matches.opt_present("verbose") {
            let flags = Flags::parse(&["build".to_string()]);
            let mut config = Config::parse(&flags.build, cfg_file.clone());
            config.build = flags.build.clone();
            let mut build = Build::new(flags, config);
            metadata::build(&mut build);
            let maybe_rules_help = step::build_rules(&build).get_help(subcommand);
            if maybe_rules_help.is_some() {
                extra_help.push_str(maybe_rules_help.unwrap().as_str());
            }
        } else {
            extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.",
                     subcommand).as_str());
        }

        // User passed in -h/--help?
        if matches.opt_present("help") {
            usage(0, &opts, &subcommand_help, &extra_help);
        }

        let cmd = match subcommand.as_str() {
            "build" => {
                Subcommand::Build { paths: paths }
            }
            "test" => {
                Subcommand::Test {
                    paths: paths,
                    test_args: matches.opt_strs("test-args"),
                    no_fail_fast: matches.opt_present("no-fail-fast"),
                }
            }
            "bench" => {
                Subcommand::Bench {
                    paths: paths,
                    test_args: matches.opt_strs("test-args"),
                }
            }
            "doc" => {
                Subcommand::Doc { paths: paths }
            }
            "clean" => {
                if paths.len() > 0 {
                    println!("\nclean takes no arguments\n");
                    usage(1, &opts, &subcommand_help, &extra_help);
                }
                Subcommand::Clean
            }
            "dist" => {
                Subcommand::Dist {
                    paths: paths,
                }
            }
            "install" => {
                Subcommand::Install {
                    paths: paths,
                }
            }
            _ => {
                usage(1, &opts, &subcommand_help, &extra_help);
            }
        };

        let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap());

        if matches.opt_present("incremental") {
            if stage.is_none() {
                stage = Some(1);
            }
        }

        Flags {
            verbose: matches.opt_count("verbose"),
            stage: stage,
            on_fail: matches.opt_str("on-fail"),
            keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
            build: matches.opt_str("build").unwrap_or_else(|| {
                env::var("BUILD").unwrap()
            }),
            host: split(matches.opt_strs("host")),
            target: split(matches.opt_strs("target")),
            config: cfg_file,
            src: matches.opt_str("src").map(PathBuf::from),
            jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
            cmd: cmd,
            incremental: matches.opt_present("incremental"),
        }
    }
}

impl Subcommand {
    pub fn test_args(&self) -> Vec<&str> {
        match *self {
            Subcommand::Test { ref test_args, .. } |
            Subcommand::Bench { ref test_args, .. } => {
                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
            }
            _ => Vec::new(),
        }
    }

    pub fn no_fail_fast(&self) -> bool {
        match *self {
            Subcommand::Test { no_fail_fast, .. } => no_fail_fast,
            _ => false,
        }
    }
}

fn split(s: Vec<String>) -> Vec<String> {
    s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
}
<|endoftext|>