<commit_before>use std::ptr;

use gc::root::IndirectObj;
use object::Obj;

pub const HANDLE_SIZE: usize = 256;

pub struct HandleMemory {
    /// all buffers, Box is important since HandleBuffer
    /// is a big struct that needs to get moved/copied on resizes
    buffers: Vec<Box<HandleBuffer>>,
    borders: Vec<BorderData>,

    // next free position in buffer
    free: usize,
}

impl HandleMemory {
    pub fn new() -> HandleMemory {
        let buffer = box HandleBuffer::new();

        HandleMemory {
            buffers: vec![buffer],
            borders: Vec::new(),
            free: 0,
        }
    }

    pub fn push(&mut self, obj: *mut Obj) -> IndirectObj {
        if self.free >= HANDLE_SIZE {
            self.push_buffer();
            self.free = 0;
        }

        let buffer = self.buffers.last_mut().unwrap();
        let elem = &mut buffer.elements[self.free];

        *elem = obj;

        (elem as *mut _ as usize).into()
    }

    fn push_buffer(&mut self) {
        self.buffers.push(box HandleBuffer::new());
    }
}

struct HandleBuffer {
    elements: [*mut Obj; HANDLE_SIZE],
}

impl HandleBuffer {
    fn new() -> HandleBuffer {
        HandleBuffer {
            elements: [ptr::null_mut(); HANDLE_SIZE],
        }
    }
}

struct BorderData {
    buffer: usize,
    element: usize,
}

struct HandleBuffer(usize);
<commit_msg>fix compile error<commit_after>use std::ptr;

use gc::root::IndirectObj;
use object::Obj;

pub const HANDLE_SIZE: usize = 256;

pub struct HandleMemory {
    /// all buffers, Box is important since HandleBuffer
    /// is a big struct that needs to get moved/copied on resizes
    buffers: Vec<Box<HandleBuffer>>,
    borders: Vec<BorderData>,

    // next free position in buffer
    free: usize,
}

impl HandleMemory {
    pub fn new() -> HandleMemory {
        let buffer = box HandleBuffer::new();

        HandleMemory {
            buffers: vec![buffer],
            borders: Vec::new(),
            free: 0,
        }
    }

    pub fn push(&mut self, obj: *mut Obj) -> IndirectObj {
        if self.free >= HANDLE_SIZE {
            self.push_buffer();
            self.free = 0;
        }

        let buffer = self.buffers.last_mut().unwrap();
        let elem = &mut buffer.elements[self.free];

        *elem = obj;

        (elem as *mut _ as usize).into()
    }

    fn push_buffer(&mut self) {
        self.buffers.push(box HandleBuffer::new());
    }
}

struct HandleBuffer {
    elements: [*mut Obj; HANDLE_SIZE],
}

impl HandleBuffer {
    fn new() -> HandleBuffer {
        HandleBuffer {
            elements: [ptr::null_mut(); HANDLE_SIZE],
        }
    }
}

struct BorderData {
    buffer: usize,
    element: usize,
}

struct HandleBorder(usize);
<|endoftext|>


<commit_before>/// Computing hashes for files.

use std::ffi::OsString;
use std::io::prelude::*;
use std::os::unix::ffi::OsStringExt;
use std::path::Path;

use openssl::crypto::hash::{self, Hasher};

use rustc_serialize::hex::ToHex;

use super::Result;
use super::suretree::{SureFile, SureTree};
use super::escape::*;
use super::progress::Progress;

pub trait SureHash {
    /// Estimate how much work (files and bytes) need to be hashed.
    fn hash_estimate(&self) -> Estimate;

    /// Update the hashes on any files that are missing them.
    /// Note that this only logs errors, and tries to continue.
    fn hash_update(&mut self, path: &Path, meter: &mut Progress);
}

#[derive(Debug)]
pub struct Estimate {
    pub files: u64,
    pub bytes: u64,
}

impl SureHash for SureTree {
    fn hash_estimate(&self) -> Estimate {
        let mut est = Estimate {
            files: 0,
            bytes: 0,
        };
        est.update(self);
        est
    }

    fn hash_update(&mut self, path: &Path, meter: &mut Progress) {
        for d in &mut self.children {
            let s: OsString = OsStringExt::from_vec(d.name.unescape().unwrap());
            let cpath = path.join(&s);
            d.hash_update(&cpath, meter);
        }

        for f in &mut self.files {
            if !f.needs_hash() {
                continue;
            }

            let s: OsString = OsStringExt::from_vec(f.name.unescape().unwrap());
            let fpath = path.join(&s);

            match noatime_open(&fpath) {
                Ok(mut fd) => {
                    match hash_file(&mut fd) {
                        Ok(h) => {
                            let hex = h.to_hex();
                            f.atts.insert("sha1".to_string(), hex);
                        },
                        Err(e) => {
                            error!("Unable to has file: '{:?}' ({})", fpath, e);
                        }
                    }
                },
                Err(e) => {
                    error!("Unable to open '{:?}' for hashing ({})", fpath, e);
                }
            }

            meter.update(1, f.atts["size"].parse().unwrap());
        }
    }
}

impl SureFile {
    fn needs_hash(&self) -> bool {
        match (self.atts.get("kind"), self.atts.get("sha1")) {
            (Some(k), None) if k == "file" => true,
            _ => false,
        }
    }
}

impl Estimate {
    fn update(&mut self, node: &SureTree) {
        for f in &node.files {
            if f.needs_hash() {
                self.files += 1;
                self.bytes += f.atts["size"].parse::<u64>().unwrap();
            }
            /*
            match (f.atts.get("kind"), f.atts.get("sha1")) {
                (Some(k), None) if k == "file" => {
                    self.files += 1;
                    self.bytes += f.atts["size"].parse::<u64>().unwrap();
                },
                _ => (),
            }
            */
        }

        for d in &node.children {
            self.update(d);
        }
    }
}

// TODO: Reuse buffer and hasher for a given thread.
fn hash_file<R: Read>(rd: &mut R) -> Result<Vec<u8>> {
    let mut h = Hasher::new(hash::Type::SHA1);
    let mut buf = vec![0u8; 8192];

    loop {
        let count = try!(rd.read(&mut buf));
        if count == 0 {
            break;
        }

        try!(h.write_all(&buf[0..count]));
    }
    Ok(h.finish())
}

use self::atime_impl::noatime_open;

/// Open the given file, trying to not update the atime if that is
/// possible.
/// Unfortunately, there isn't a clean way to do this with Rust's library,
/// so we hack.  This isn't completely safe, because we rely on the
/// structure being encoded the same way.
#[cfg(target_os = "linux")]
mod atime_impl {
    use libc;
    use std::fs::{File, OpenOptions};
    use std::io;
    use std::mem;
    use std::path::Path;

    pub fn noatime_open(name: &Path) -> io::Result<File> {
        // Try opening it first with noatime, and if that fails, try the open
        // again without the option.
        match OpenOptions::new().read(true).noatime().open(name) {
            Ok(f) => Ok(f),
            Err(_) =>
                OpenOptions::new().read(true).open(name)
        }
    }

    trait HackNoAtime {
        fn noatime(&mut self) -> &mut Self;
    }

    impl HackNoAtime for OpenOptions {
        fn noatime(&mut self) -> &mut Self {
            unsafe {
                let ptr: *mut MyOpenOption = mem::transmute(self as *mut OpenOptions);
                (*ptr).0.flags |= 0o1000000;
            }
            self
        }
    }

    struct MyOpenOption(MyOpenOptionImp);
    struct MyOpenOptionImp {
        flags: libc::c_int,
        // ...
    }
}

// Other platforms, just use normal open.
#[cfg(not(target_os = "linux"))]
mod atime_impl {
    use std::fs::{File, OpenOptions};
    use std::path::Path;
    use std::io;

    pub fn noatime_open(name: &Path) -> io::Result<File> {
        OpenOptions::new().read(true).open(name)
    }
}
<commit_msg>Eliminate unsafe NOATIME<commit_after>/// Computing hashes for files.

use std::ffi::OsString;
use std::io::prelude::*;
use std::os::unix::ffi::OsStringExt;
use std::path::Path;

use openssl::crypto::hash::{self, Hasher};

use rustc_serialize::hex::ToHex;

use super::Result;
use super::suretree::{SureFile, SureTree};
use super::escape::*;
use super::progress::Progress;

pub trait SureHash {
    /// Estimate how much work (files and bytes) need to be hashed.
    fn hash_estimate(&self) -> Estimate;

    /// Update the hashes on any files that are missing them.
    /// Note that this only logs errors, and tries to continue.
    fn hash_update(&mut self, path: &Path, meter: &mut Progress);
}

#[derive(Debug)]
pub struct Estimate {
    pub files: u64,
    pub bytes: u64,
}

impl SureHash for SureTree {
    fn hash_estimate(&self) -> Estimate {
        let mut est = Estimate {
            files: 0,
            bytes: 0,
        };
        est.update(self);
        est
    }

    fn hash_update(&mut self, path: &Path, meter: &mut Progress) {
        for d in &mut self.children {
            let s: OsString = OsStringExt::from_vec(d.name.unescape().unwrap());
            let cpath = path.join(&s);
            d.hash_update(&cpath, meter);
        }

        for f in &mut self.files {
            if !f.needs_hash() {
                continue;
            }

            let s: OsString = OsStringExt::from_vec(f.name.unescape().unwrap());
            let fpath = path.join(&s);

            match noatime_open(&fpath) {
                Ok(mut fd) => {
                    match hash_file(&mut fd) {
                        Ok(h) => {
                            let hex = h.to_hex();
                            f.atts.insert("sha1".to_string(), hex);
                        },
                        Err(e) => {
                            error!("Unable to has file: '{:?}' ({})", fpath, e);
                        }
                    }
                },
                Err(e) => {
                    error!("Unable to open '{:?}' for hashing ({})", fpath, e);
                }
            }

            meter.update(1, f.atts["size"].parse().unwrap());
        }
    }
}

impl SureFile {
    fn needs_hash(&self) -> bool {
        match (self.atts.get("kind"), self.atts.get("sha1")) {
            (Some(k), None) if k == "file" => true,
            _ => false,
        }
    }
}

impl Estimate {
    fn update(&mut self, node: &SureTree) {
        for f in &node.files {
            if f.needs_hash() {
                self.files += 1;
                self.bytes += f.atts["size"].parse::<u64>().unwrap();
            }
            /*
            match (f.atts.get("kind"), f.atts.get("sha1")) {
                (Some(k), None) if k == "file" => {
                    self.files += 1;
                    self.bytes += f.atts["size"].parse::<u64>().unwrap();
                },
                _ => (),
            }
            */
        }

        for d in &node.children {
            self.update(d);
        }
    }
}

// TODO: Reuse buffer and hasher for a given thread.
fn hash_file<R: Read>(rd: &mut R) -> Result<Vec<u8>> {
    let mut h = Hasher::new(hash::Type::SHA1);
    let mut buf = vec![0u8; 8192];

    loop {
        let count = try!(rd.read(&mut buf));
        if count == 0 {
            break;
        }

        try!(h.write_all(&buf[0..count]));
    }
    Ok(h.finish())
}

use self::atime_impl::noatime_open;

/// Open the given file, trying to not update the atime if that is
/// possible.
/// The `custom_flags` method is only stable since Rust 1.10.0.
#[cfg(target_os = "linux")]
mod atime_impl {
    use std::fs::{File, OpenOptions};
    use std::os::unix::fs::OpenOptionsExt;
    use std::io;
    use std::path::Path;

    // From linux's fcntl.h, not exported in the libc crate.
    const O_NOATIME: i32 = 0o1000000;

    pub fn noatime_open(name: &Path) -> io::Result<File> {
        // Try opening it first with noatime, and if that fails, try the open
        // again without the option.
        match OpenOptions::new().read(true)
            .custom_flags(O_NOATIME)
            .open(name)
        {
            Ok(f) => Ok(f),
            Err(_) =>
                OpenOptions::new().read(true).open(name)
        }
    }
}

// Other platforms, just use normal open.
#[cfg(not(target_os = "linux"))]
mod atime_impl {
    use std::fs::{File, OpenOptions};
    use std::path::Path;
    use std::io;

    pub fn noatime_open(name: &Path) -> io::Result<File> {
        OpenOptions::new().read(true).open(name)
    }
}
<|endoftext|>


<commit_before>//! Audio IO from WAV files.

use byteorder::{self, ReadBytesExt, WriteBytesExt, LittleEndian};
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::path::Path;

use error::{Error, Result};
use types::{SAMPLE_RATE, AudioDevice, Time, Sample};

/// Reads audio from a wav file.
///
/// The reader will continue until it runs out of samples. When it does, the
/// reader will return silence until it is reset to the beginning of the file.
pub struct WavReader<R: Read> {
    num_channels: usize,
    num_samples: Time,
    samples_read: Time,
    reader: R
}

impl WavReader<File> {
    /// Returns a `WavReader` reading the provided file.
    pub fn open<P: AsRef<Path>>(filename: P) -> Result<Self> {
        let file = try!(File::open(filename));
        WavReader::new(file)
    }
}

impl<R: Read> WavReader<R> {
    /// Retuns a `WavReader` reading anything implementing `Read`.
    pub fn new(mut reader: R) -> Result<Self> {
        let header = try!(WavHeader::read_from_file(&mut reader));
        Ok(WavReader {
            num_channels: header.num_channels as usize,
            num_samples: (header.data_size / ((header.bit_depth/8) as u32) /
                (header.num_channels as u32)) as Time,
            samples_read: 0,
            reader: reader
        })
    }

    /// Returns the number of audio samples in the wav file.
    pub fn get_num_samples(&self) -> Time {
        self.num_samples
    }

    /// Returns true if we have read the entire wav file.
    pub fn is_done(&self) -> bool {
        self.samples_read >= self.num_samples
    }
}

impl<R: Read+Seek> WavReader<R> {
    /// Resets the reader to begin reading from the start of the file.
    pub fn restart(&mut self) -> io::Result<u64> {
        self.samples_read = 0;
        self.reader.seek(SeekFrom::Start(44))
    }
}

impl<R: Read> AudioDevice for WavReader<R> {
    fn num_inputs(&self) -> usize {
        0
    }

    fn num_outputs(&self) -> usize {
        self.num_channels
    }

    fn tick(&mut self, _: Time, _: &[Sample], outputs: &mut[Sample]) {
        for i in 0..self.num_channels {
            let s = if self.samples_read < self.num_samples {
                let n = self.reader.read_i16::<LittleEndian>()
                    .expect("Failed to read next sample from wav.");
                (n as Sample) / 32768.0
            } else {
                0.0
            };
            outputs[i] = s;
        }
        self.samples_read += 1;
    }
}

/// Writes audio to a wav file.
///
/// The writer initializes the data_size to be 0. This will not be overwritten
/// with the proper size until `update_data_size` is called.
///
/// While `WavReader` only requires its type be `Seek` to use the `restart`
/// method, the `WavWriter` reqiures `Seek` for all types, because the final
/// data size must be written to the header when the writer leaves scope.
pub struct WavWriter<W: Write+Seek> {
    num_channels: usize,
    samples_written: usize,
    writer: W,
}

impl WavWriter<File> {
    /// Returns a `WavWriter` writing to the provided file.
    pub fn create<P: AsRef<Path>>(filename: P, num_channels: usize)
            -> Result<Self> {
        let file = try!(File::create(filename));
        WavWriter::new(file, num_channels)
    }
}

impl<W: Write+Seek> WavWriter<W> {
    /// Returns a `WavWriter` writing to anything implementing `Write`.
    pub fn new(mut writer: W, num_channels: usize) -> Result<Self> {
        let header = WavHeader::new(num_channels as u16, SAMPLE_RATE as u32,
                                    0u32);
        try!(header.write_to_file(&mut writer));
        Ok(WavWriter {
            num_channels: num_channels,
            samples_written: 0,
            writer: writer,
        })
    }
}

impl<W: Write+Seek> Drop for WavWriter<W> {
    fn drop(&mut self) {
        // Updates the wav header to have the correct amount of data written
        let data_size = self.samples_written * self.num_channels * 16/8;
        let file_size = 36+data_size;
        self.writer.seek(SeekFrom::Start(4))
            .expect("Failed to seek wav file size.");
        self.writer.write_u32::<LittleEndian>(file_size as u32)
            .expect("Failed to write wav file size.");
        self.writer.seek(SeekFrom::Start(40))
            .expect("Failed to seek wav data size.");
        self.writer.write_u32::<LittleEndian>(data_size as u32)
            .expect("Failed to write wav data size.");
    }
}

impl<W: Write+Seek> AudioDevice for WavWriter<W> {
    fn num_inputs(&self) -> usize {
        self.num_channels
    }

    fn num_outputs(&self) -> usize {
        0
    }

    fn tick(&mut self, _: Time, inputs: &[Sample], _: &mut[Sample]) {
        for s in inputs.iter() {
            let mut clipped = *s;
            if clipped > 0.999f32 { clipped = 0.999f32; }
            if clipped < -0.999f32 { clipped = -0.999f32; }
            self.writer.write_i16::<LittleEndian>((clipped*32768.0) as i16)
                .expect("Failed to write next sample to wav file.");
        }
        self.samples_written += 1;
    }
}

/// Constants for the strings used in a wav header
static RIFF: u32 = 0x46464952;
static WAVE: u32 = 0x45564157;
static FMT_: u32 = 0x20746d66;
static DATA: u32 = 0x61746164;

/// A struct container for the wav header
#[derive(Clone, Debug)]
struct WavHeader {
    riff_hdr: u32,
    file_size: u32,
    wave_lbl: u32,
    fmt_hdr: u32,
    section_size: u32,
    format: u16,
    num_channels: u16,
    sample_rate: u32,
    byte_rate: u32,
    block_align: u16,
    bit_depth: u16,
    data_hdr: u32,
    data_size: u32,
}

impl WavHeader {
    /// Returns a new wav header with all values initalized for our supported
    /// audio formats
    fn new(num_channels: u16, sample_rate: u32, data_size: u32) -> Self {
        WavHeader {
            riff_hdr: RIFF,
            file_size: data_size+36,
            wave_lbl: WAVE,
            fmt_hdr: FMT_,
            section_size: 16,
            format: 1,
            num_channels: num_channels,
            sample_rate: sample_rate,
            byte_rate: sample_rate*(num_channels as u32)*16/8,
            block_align: num_channels*16/8,
            bit_depth: 16,
            data_hdr: DATA,
            data_size: data_size,
        }
    }

    /// Attempts to read a wav header from the provided file
    fn read_from_file<R: Read>(f: &mut R) -> Result<Self> {
        let riff_hdr = try!(f.read_u32::<LittleEndian>());
        let file_size = try!(f.read_u32::<LittleEndian>());
        let wave_lbl = try!(f.read_u32::<LittleEndian>());
        let fmt_hdr = try!(f.read_u32::<LittleEndian>());
        let section_size = try!(f.read_u32::<LittleEndian>());
        let format = try!(f.read_u16::<LittleEndian>());
        let num_channels = try!(f.read_u16::<LittleEndian>());
        let sample_rate = try!(f.read_u32::<LittleEndian>());
        let byte_rate = try!(f.read_u32::<LittleEndian>());
        let block_align = try!(f.read_u16::<LittleEndian>());
        let bit_depth = try!(f.read_u16::<LittleEndian>());
        let data_hdr = try!(f.read_u32::<LittleEndian>());
        let data_size = try!(f.read_u32::<LittleEndian>());
        let header = WavHeader {
            riff_hdr: riff_hdr,
            file_size: file_size,
            wave_lbl: wave_lbl,
            fmt_hdr: fmt_hdr,
            section_size: section_size,
            format: format,
            num_channels: num_channels,
            sample_rate: sample_rate,
            byte_rate: byte_rate,
            block_align: block_align,
            bit_depth: bit_depth,
            data_hdr: data_hdr,
            data_size: data_size
        };
        header.check()
    }

    /// Returns the header if the wav header has valid fields and uses the
    /// supported formats, otherwise return a descriptive error
    fn check(self) -> Result<Self> {
        // Check the headers are correct
        if self.riff_hdr != RIFF { return Err(Error::InvalidFile); }
        if self.wave_lbl != WAVE { return Err(Error::InvalidFile); }
        if self.fmt_hdr  != FMT_ { return Err(Error::InvalidFile); }
        if self.data_hdr != DATA { return Err(Error::InvalidFile); }

        // Check sizes are correct
        if self.file_size != self.data_size + 36 {
            return Err(Error::InvalidFile);
        }
        if self.section_size != 16 {
            return Err(Error::InvalidFile);
        }
        if self.byte_rate != self.sample_rate*(self.num_channels as u32)*
            (self.bit_depth as u32)/8 {
            return Err(Error::InvalidFile);
        }
        if self.block_align != self.num_channels*self.bit_depth/8 {
            return Err(Error::InvalidFile);
        }

        // Check for formats we can read
        if self.format != 1 {
            return Err(Error::Unsupported("Only PCM is supported"));
        }
        if self.sample_rate != (SAMPLE_RATE as u32) {
            return Err(Error::Unsupported(
                    "Sample rate conversion not supported"));
        }
        if self.bit_depth != 16 {
            return Err(Error::Unsupported("Only 16-bit supported"));
        }

        // If this header is valid, then return it instead
        Ok(self)
    }

    /// Attempts to write this wav header to the provided file
    fn write_to_file<W: Write>(&self, w: &mut W) -> byteorder::Result<()> {
        w.write_u32::<LittleEndian>(self.riff_hdr)
            .and_then(|()| w.write_u32::<LittleEndian>(self.file_size))
            .and_then(|()| w.write_u32::<LittleEndian>(self.wave_lbl))
            .and_then(|()| w.write_u32::<LittleEndian>(self.fmt_hdr))
            .and_then(|()| w.write_u32::<LittleEndian>(self.section_size))
            .and_then(|()| w.write_u16::<LittleEndian>(self.format))
            .and_then(|()| w.write_u16::<LittleEndian>(self.num_channels))
            .and_then(|()| w.write_u32::<LittleEndian>(self.sample_rate))
            .and_then(|()| w.write_u32::<LittleEndian>(self.byte_rate))
            .and_then(|()| w.write_u16::<LittleEndian>(self.block_align))
            .and_then(|()| w.write_u16::<LittleEndian>(self.bit_depth))
            .and_then(|()| w.write_u32::<LittleEndian>(self.data_hdr))
            .and_then(|()| w.write_u32::<LittleEndian>(self.data_size))
    }
}
<commit_msg>Add wav tests<commit_after>//! Audio IO from WAV files.

use byteorder::{self, ReadBytesExt, WriteBytesExt, LittleEndian};
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::path::Path;

use error::{Error, Result};
use types::{SAMPLE_RATE, AudioDevice, Time, Sample};

/// Reads audio from a wav file.
///
/// The reader will continue until it runs out of samples. When it does, the
/// reader will return silence until it is reset to the beginning of the file.
pub struct WavReader<R: Read> {
    num_channels: usize,
    num_samples: Time,
    samples_read: Time,
    reader: R
}

impl WavReader<File> {
    /// Returns a `WavReader` reading the provided file.
    pub fn open<P: AsRef<Path>>(filename: P) -> Result<Self> {
        let file = try!(File::open(filename));
        WavReader::new(file)
    }
}

impl<R: Read> WavReader<R> {
    /// Retuns a `WavReader` reading anything implementing `Read`.
    pub fn new(mut reader: R) -> Result<Self> {
        let header = try!(WavHeader::read_from_file(&mut reader));
        Ok(WavReader {
            num_channels: header.num_channels as usize,
            num_samples: (header.data_size / ((header.bit_depth/8) as u32) /
                (header.num_channels as u32)) as Time,
            samples_read: 0,
            reader: reader
        })
    }

    /// Returns the number of audio samples in the wav file.
    pub fn get_num_samples(&self) -> Time {
        self.num_samples
    }

    /// Returns true if we have read the entire wav file.
    pub fn is_done(&self) -> bool {
        self.samples_read >= self.num_samples
    }
}

impl<R: Read+Seek> WavReader<R> {
    /// Resets the reader to begin reading from the start of the file.
    pub fn restart(&mut self) -> io::Result<u64> {
        self.samples_read = 0;
        self.reader.seek(SeekFrom::Start(44))
    }
}

impl<R: Read> AudioDevice for WavReader<R> {
    fn num_inputs(&self) -> usize {
        0
    }

    fn num_outputs(&self) -> usize {
        self.num_channels
    }

    fn tick(&mut self, _: Time, _: &[Sample], outputs: &mut[Sample]) {
        for i in 0..self.num_channels {
            let s = if self.samples_read < self.num_samples {
                let n = self.reader.read_i16::<LittleEndian>()
                    .expect("Failed to read next sample from wav.");
                (n as Sample) / 32768.0
            } else {
                0.0
            };
            outputs[i] = s;
        }
        self.samples_read += 1;
    }
}

/// Writes audio to a wav file.
///
/// The writer initializes the data_size to be 0. This will not be overwritten
/// with the proper size until `update_data_size` is called.
///
/// While `WavReader` only requires its type be `Seek` to use the `restart`
/// method, the `WavWriter` reqiures `Seek` for all types, because the final
/// data size must be written to the header when the writer leaves scope.
pub struct WavWriter<W: Write+Seek> {
    num_channels: usize,
    samples_written: usize,
    writer: W,
}

impl WavWriter<File> {
    /// Returns a `WavWriter` writing to the provided file.
    pub fn create<P: AsRef<Path>>(filename: P, num_channels: usize)
            -> Result<Self> {
        let file = try!(File::create(filename));
        WavWriter::new(file, num_channels)
    }
}

impl<W: Write+Seek> WavWriter<W> {
    /// Returns a `WavWriter` writing to anything implementing `Write`.
    pub fn new(mut writer: W, num_channels: usize) -> Result<Self> {
        let header = WavHeader::new(num_channels as u16, SAMPLE_RATE as u32,
                                    0u32);
        try!(header.write_to_file(&mut writer));
        Ok(WavWriter {
            num_channels: num_channels,
            samples_written: 0,
            writer: writer,
        })
    }
}

impl<W: Write+Seek> Drop for WavWriter<W> {
    fn drop(&mut self) {
        // Updates the wav header to have the correct amount of data written
        let data_size = self.samples_written * self.num_channels * 16/8;
        let file_size = 36+data_size;
        self.writer.seek(SeekFrom::Start(4))
            .expect("Failed to seek wav file size.");
        self.writer.write_u32::<LittleEndian>(file_size as u32)
            .expect("Failed to write wav file size.");
        self.writer.seek(SeekFrom::Start(40))
            .expect("Failed to seek wav data size.");
        self.writer.write_u32::<LittleEndian>(data_size as u32)
            .expect("Failed to write wav data size.");
    }
}

impl<W: Write+Seek> AudioDevice for WavWriter<W> {
    fn num_inputs(&self) -> usize {
        self.num_channels
    }

    fn num_outputs(&self) -> usize {
        0
    }

    fn tick(&mut self, _: Time, inputs: &[Sample], _: &mut[Sample]) {
        for s in inputs.iter() {
            let mut clipped = *s;
            if clipped > 0.9999695 { clipped = 0.9999695; }
            if clipped < -1.0 { clipped = 1.0; }
            self.writer.write_i16::<LittleEndian>((clipped*32768.0) as i16)
                .expect("Failed to write next sample to wav file.");
        }
        self.samples_written += 1;
    }
}

/// Constants for the strings used in a wav header
static RIFF: u32 = 0x46464952;
static WAVE: u32 = 0x45564157;
static FMT_: u32 = 0x20746d66;
static DATA: u32 = 0x61746164;

/// A struct container for the wav header
#[derive(Clone, Debug)]
struct WavHeader {
    riff_hdr: u32,
    file_size: u32,
    wave_lbl: u32,
    fmt_hdr: u32,
    section_size: u32,
    format: u16,
    num_channels: u16,
    sample_rate: u32,
    byte_rate: u32,
    block_align: u16,
    bit_depth: u16,
    data_hdr: u32,
    data_size: u32,
}

impl WavHeader {
    /// Returns a new wav header with all values initalized for our supported
    /// audio formats
    fn new(num_channels: u16, sample_rate: u32, data_size: u32) -> Self {
        WavHeader {
            riff_hdr: RIFF,
            file_size: data_size+36,
            wave_lbl: WAVE,
            fmt_hdr: FMT_,
            section_size: 16,
            format: 1,
            num_channels: num_channels,
            sample_rate: sample_rate,
            byte_rate: sample_rate*(num_channels as u32)*16/8,
            block_align: num_channels*16/8,
            bit_depth: 16,
            data_hdr: DATA,
            data_size: data_size,
        }
    }

    /// Attempts to read a wav header from the provided file
    fn read_from_file<R: Read>(f: &mut R) -> Result<Self> {
        let riff_hdr = try!(f.read_u32::<LittleEndian>());
        let file_size = try!(f.read_u32::<LittleEndian>());
        let wave_lbl = try!(f.read_u32::<LittleEndian>());
        let fmt_hdr = try!(f.read_u32::<LittleEndian>());
        let section_size = try!(f.read_u32::<LittleEndian>());
        let format = try!(f.read_u16::<LittleEndian>());
        let num_channels = try!(f.read_u16::<LittleEndian>());
        let sample_rate = try!(f.read_u32::<LittleEndian>());
        let byte_rate = try!(f.read_u32::<LittleEndian>());
        let block_align = try!(f.read_u16::<LittleEndian>());
        let bit_depth = try!(f.read_u16::<LittleEndian>());
        let data_hdr = try!(f.read_u32::<LittleEndian>());
        let data_size = try!(f.read_u32::<LittleEndian>());
        let header = WavHeader {
            riff_hdr: riff_hdr,
            file_size: file_size,
            wave_lbl: wave_lbl,
            fmt_hdr: fmt_hdr,
            section_size: section_size,
            format: format,
            num_channels: num_channels,
            sample_rate: sample_rate,
            byte_rate: byte_rate,
            block_align: block_align,
            bit_depth: bit_depth,
            data_hdr: data_hdr,
            data_size: data_size
        };
        header.check()
    }

    /// Returns the header if the wav header has valid fields and uses the
    /// supported formats, otherwise return a descriptive error
    fn check(self) -> Result<Self> {
        // Check the headers are correct
        if self.riff_hdr != RIFF { return Err(Error::InvalidFile); }
        if self.wave_lbl != WAVE { return Err(Error::InvalidFile); }
        if self.fmt_hdr  != FMT_ { return Err(Error::InvalidFile); }
        if self.data_hdr != DATA { return Err(Error::InvalidFile); }

        // Check sizes are correct
        if self.file_size != self.data_size + 36 {
            return Err(Error::InvalidFile);
        }
        if self.section_size != 16 {
            return Err(Error::InvalidFile);
        }
        if self.byte_rate != self.sample_rate*(self.num_channels as u32)*
            (self.bit_depth as u32)/8 {
            return Err(Error::InvalidFile);
        }
        if self.block_align != self.num_channels*self.bit_depth/8 {
            return Err(Error::InvalidFile);
        }

        // Check for formats we can read
        if self.format != 1 {
            return Err(Error::Unsupported("Only PCM is supported"));
        }
        if self.sample_rate != (SAMPLE_RATE as u32) {
            return Err(Error::Unsupported(
                    "Sample rate conversion not supported"));
        }
        if self.bit_depth != 16 {
            return Err(Error::Unsupported("Only 16-bit supported"));
        }

        // If this header is valid, then return it instead
        Ok(self)
    }

    /// Attempts to write this wav header to the provided file
    fn write_to_file<W: Write>(&self, w: &mut W) -> byteorder::Result<()> {
        w.write_u32::<LittleEndian>(self.riff_hdr)
            .and_then(|()| w.write_u32::<LittleEndian>(self.file_size))
            .and_then(|()| w.write_u32::<LittleEndian>(self.wave_lbl))
            .and_then(|()| w.write_u32::<LittleEndian>(self.fmt_hdr))
            .and_then(|()| w.write_u32::<LittleEndian>(self.section_size))
            .and_then(|()| w.write_u16::<LittleEndian>(self.format))
            .and_then(|()| w.write_u16::<LittleEndian>(self.num_channels))
            .and_then(|()| w.write_u32::<LittleEndian>(self.sample_rate))
            .and_then(|()| w.write_u32::<LittleEndian>(self.byte_rate))
            .and_then(|()| w.write_u16::<LittleEndian>(self.block_align))
            .and_then(|()| w.write_u16::<LittleEndian>(self.bit_depth))
            .and_then(|()| w.write_u32::<LittleEndian>(self.data_hdr))
            .and_then(|()| w.write_u32::<LittleEndian>(self.data_size))
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use types::AudioDevice;
    use super::{WavHeader, WavReader, WavWriter};

    static WAV_HEADER: [u8; 48] =
        [0x52, 0x49, 0x46, 0x46, 0x28, 0x00, 0x00, 0x00, 0x57, 0x41,
         0x56, 0x45, 0x66, 0x6D, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00,
         0x01, 0x00, 0x02, 0x00, 0x44, 0xAC, 0x00, 0x00, 0x10, 0xB1,
         0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61,
         0x04, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x7F];

    #[test]
    fn test_read_wav_header() {
        let mut cursor = Cursor::new(&WAV_HEADER[..]);
        let header = WavHeader::read_from_file(&mut cursor).unwrap();
        assert_eq!(header.bit_depth, 16);
        assert_eq!(header.data_size, 4);
        assert_eq!(header.num_channels, 2);
    }

    #[test]
    fn test_wav_reader() {
        let cursor = Cursor::new(&WAV_HEADER[..]);
        let mut reader = WavReader::new(cursor).unwrap();
        assert_eq!(reader.num_inputs(), 0);
        assert_eq!(reader.num_outputs(), 2);
        assert_eq!(reader.get_num_samples(), 1);
        assert_eq!(reader.is_done(), false);

        let mut output = [0.0, 0.0];
        reader.tick(0, &[], &mut output);
        assert_eq!(reader.is_done(), true);
        assert_eq!(output, [-1.0, 0.9999695]);

        reader.tick(1, &[], &mut output);
        assert_eq!(reader.is_done(), true);
        assert_eq!(output, [0.0, 0.0]);
    }

    #[test]
    fn test_wav_writer() {
        let mut buffer = [0u8; 48];
        {
            // Scope the cursor so its borrow on the buffer ends.
            // Scope the writer so it gets dropped and the file size written.
            let cursor = Cursor::new(&mut buffer[..]);
            let mut writer = WavWriter::new(cursor, 2).unwrap();
            assert_eq!(writer.num_inputs(), 2);
            assert_eq!(writer.num_outputs(), 0);
            writer.tick(0, &[-1.0, 0.9999695], &mut[]);
        }
        assert_eq!(&buffer[..], &WAV_HEADER[..]);
    }
}
<|endoftext|>


<commit_before>
use std::fmt;
use std::io::Read;  // Trait providing read_to_string()
use std::env;

use hyper;
use serde;
use serde_json;

use Version;
use Projects;
use BuildQuery;
use Groups;
// use Listing;

pub const API_VERSION: u16 = 3;

#[derive(Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

// Explicitly implement Debug trait for GitLab so we can hide the token.
impl fmt::Debug for GitLab {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "GitLab {{ scheme: {}, domain: {}, port: {}, private_token: XXXXXXXXXXXXXXXXXXXX, \
                client: {:?}, pagination: {:?} }}",
               self.scheme,
               self.domain,
               self.port,
               self.client,
               self.pagination)
    }
}

impl GitLab {
    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port: port,
            private_token: private_token.to_string(),
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                }
                Err(_) => hyper::Client::new(),
            },
            pagination: Pagination {
                page: 1,
                per_page: 20,
            },
        }
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", &domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", &domain, 443, &private_token)
    }

    /// Build a URL used to access GitLab instance, including some parameters.
    ///
    /// # Examples
    ///
    /// Example from GitLab: https://docs.gitlab.com/ce/api/#basic-usage
    ///
    /// ```
    /// use gitlab_api::GitLab;
    ///
    /// let expected_url = "https://gitlab.example.com:\
    ///                     443/api/v3/groups?\
    ///                     order_by=path&private_token=XXXXXXXXXXXXX&page=1&per_page=20";
    ///
    /// let gl = GitLab::new_https("gitlab.example.com", "XXXXXXXXXXXXX");
    ///
    /// assert_eq!(gl.build_url("groups?order_by=path"), expected_url);
    /// ```
    pub fn build_url(&self, query: &str) -> String {
        let expected_url = "https://gitlab.example.com:\
                            443/api/v3/groups?\
                            order_by=path&private_token=XXXXXXXXXXXXX&page=1&per_page=20";

        let mut params_splitter = "?";
        if query.find("?").is_some() {
            params_splitter = "&";
        }
        format!("{}://{}:{}/api/v{}/{}{}private_token={}&page={}&per_page={}",
                self.scheme,
                self.domain,
                self.port,
                API_VERSION,
                query,
                params_splitter,
                self.private_token,
                self.pagination.page,
                self.pagination.per_page)
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        let url = self.build_url("version");
        // Close connections after each GET.
        let res = self.client.get(&url).header(hyper::header::Connection::close()).send();

        res
    }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = pagination;
    }

    pub fn get<T>(&self, query: &str) -> Result<T, serde_json::Error>
        where T: serde::Deserialize
    {
        let url = self.build_url(&query);
        info!("url: {:?}", url);
        let mut res: hyper::client::Response = self.client
            .get(&url)
            .header(hyper::header::Connection::close())
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        debug!("body: {:?}", body);

        // FIXME: Properly handle the error. Will require defining our own errors...
        assert_eq!(res.status, hyper::status::StatusCode::Ok);

        serde_json::from_str(&body.as_str())
    }

    // pub fn version(&self) -> Result<Version, serde_json::Error> {
    //     self.get("version")
    // }
    //
    // pub fn groups(&self) -> Result<Groups, serde_json::Error> {
    //     self.get("groups")
    // }
    //
    // pub fn projects(&self) -> Result<Projects, serde_json::Error> {
    //     self.get("projects")
    // }

    pub fn groups(&mut self, listing: ::groups::Listing) -> Result<Groups, serde_json::Error> {
        let query = listing.build_query();
        self.get(&query)
    }

    pub fn owned_groups(&mut self) -> Result<Groups, serde_json::Error> {
        let query = ::groups::owned_groups::Listing::new().build_query();
        info!("query: {:?}", query);
        self.get(&query)
    }
}

// #[cfg(test)]
// mod tests {
//
// #[test]
// fn it_works() {
// }
// }
//
<commit_msg>let_and_return<commit_after>
use std::fmt;
use std::io::Read;  // Trait providing read_to_string()
use std::env;

use hyper;
use serde;
use serde_json;

use Version;
use Projects;
use BuildQuery;
use Groups;
// use Listing;

pub const API_VERSION: u16 = 3;

#[derive(Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

// Explicitly implement Debug trait for GitLab so we can hide the token.
impl fmt::Debug for GitLab {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "GitLab {{ scheme: {}, domain: {}, port: {}, private_token: XXXXXXXXXXXXXXXXXXXX, \
                client: {:?}, pagination: {:?} }}",
               self.scheme,
               self.domain,
               self.port,
               self.client,
               self.pagination)
    }
}

impl GitLab {
    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port: port,
            private_token: private_token.to_string(),
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                }
                Err(_) => hyper::Client::new(),
            },
            pagination: Pagination {
                page: 1,
                per_page: 20,
            },
        }
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", &domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", &domain, 443, &private_token)
    }

    /// Build a URL used to access GitLab instance, including some parameters.
    ///
    /// # Examples
    ///
    /// Example from GitLab: https://docs.gitlab.com/ce/api/#basic-usage
    ///
    /// ```
    /// use gitlab_api::GitLab;
    ///
    /// let expected_url = "https://gitlab.example.com:\
    ///                     443/api/v3/groups?\
    ///                     order_by=path&private_token=XXXXXXXXXXXXX&page=1&per_page=20";
    ///
    /// let gl = GitLab::new_https("gitlab.example.com", "XXXXXXXXXXXXX");
    ///
    /// assert_eq!(gl.build_url("groups?order_by=path"), expected_url);
    /// ```
    pub fn build_url(&self, query: &str) -> String {
        let expected_url = "https://gitlab.example.com:\
                            443/api/v3/groups?\
                            order_by=path&private_token=XXXXXXXXXXXXX&page=1&per_page=20";

        let mut params_splitter = "?";
        if query.find("?").is_some() {
            params_splitter = "&";
        }
        format!("{}://{}:{}/api/v{}/{}{}private_token={}&page={}&per_page={}",
                self.scheme,
                self.domain,
                self.port,
                API_VERSION,
                query,
                params_splitter,
                self.private_token,
                self.pagination.page,
                self.pagination.per_page)
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        let url = self.build_url("version");
        // Close connections after each GET.
        self.client.get(&url).header(hyper::header::Connection::close()).send()
    }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = pagination;
    }

    pub fn get<T>(&self, query: &str) -> Result<T, serde_json::Error>
        where T: serde::Deserialize
    {
        let url = self.build_url(&query);
        info!("url: {:?}", url);
        let mut res: hyper::client::Response = self.client
            .get(&url)
            .header(hyper::header::Connection::close())
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        debug!("body: {:?}", body);

        // FIXME: Properly handle the error. Will require defining our own errors...
        assert_eq!(res.status, hyper::status::StatusCode::Ok);

        serde_json::from_str(&body.as_str())
    }

    // pub fn version(&self) -> Result<Version, serde_json::Error> {
    //     self.get("version")
    // }
    //
    // pub fn groups(&self) -> Result<Groups, serde_json::Error> {
    //     self.get("groups")
    // }
    //
    // pub fn projects(&self) -> Result<Projects, serde_json::Error> {
    //     self.get("projects")
    // }

    pub fn groups(&mut self, listing: ::groups::Listing) -> Result<Groups, serde_json::Error> {
        let query = listing.build_query();
        self.get(&query)
    }

    pub fn owned_groups(&mut self) -> Result<Groups, serde_json::Error> {
        let query = ::groups::owned_groups::Listing::new().build_query();
        info!("query: {:?}", query);
        self.get(&query)
    }
}

// #[cfg(test)]
// mod tests {
//
// #[test]
// fn it_works() {
// }
// }
//
<|endoftext|>


<commit_before>// Brief implementation of the 'node-google'
// node.js package.
use std::io::Read;

use super::hyper::Client;
use super::hyper::header::Connection;

use super::select::document::Document;
use super::select::predicate::Class;
use super::select::predicate::Name;
use super::select::predicate::And;

use super::regex::Regex;

#[derive(Debug)]
pub struct GoogleResult {
    pub link: String,
}

impl GoogleResult {
    pub fn new(link: &str) -> Self {
        GoogleResult { link: String::from(link) }
    }
}

#[derive(Debug)]
pub struct Google {
    per_page: usize,
    client: Client,
}

impl Default for Google {
    fn default() -> Self {
        Google {
            per_page: 10,
            client: Client::new(),
        }
    }
}

impl Google {
    pub fn google(&self, query: &str) -> Vec<GoogleResult> {
        let body = self.request(query);
        self.get_links(&body)
    }

    fn request(&self, query: &str) -> String {
        let url = format!("https://www.google.\
                           com/search?hl=en&q={}&start=0&sa=N&num={}&ie=UTF-8&oe=UTF-8&gws_rd=ssl",
                          query,
                          self.per_page);

        let mut res = self.client
                          .get(&url)
                          .header(Connection::close())
                          .send()
                          .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        body
    }

    fn get_links(&self, body: &str) -> Vec<GoogleResult> {
        let doc = Document::from(body);

        let item_selector = And(Name("div"), Class("g"));
        let link_container_selector = And(Name("h3"), Class("r"));
        let link_selector = Name("a");
        let cleaning_regex = Regex::new(r"(/url\?q=)(?P<link>.*)&(sa=.*&?)(ved=.*&?)(usg=.*&?)")
                                 .unwrap();

        let mut results = Vec::new();

        for item in doc.find(item_selector).iter().take(self.per_page) {
            let link_container;
            match item.find(link_container_selector).first() {
                Some(container) => {
                    link_container = container;
                }
                None => {
                    continue;
                }
            };

            let link_node = link_container.find(link_selector).first().unwrap();
            let link_href = link_node.attr("href").unwrap();

            if link_href.contains("/search?q=") {
                continue;
            }

            let clean_link = cleaning_regex.captures(&link_href)
                                           .unwrap()
                                           .name("link")
                                           .unwrap();

            results.push(GoogleResult::new(&clean_link));
        }

        results
    }
}
<commit_msg>Tests.<commit_after>// Brief implementation of the 'node-google'
// node.js package.
use std::io::Read;

use super::hyper::Client;
use super::hyper::header::Connection;

use super::select::document::Document;
use super::select::predicate::Class;
use super::select::predicate::Name;
use super::select::predicate::And;

use super::regex::Regex;

#[derive(Debug)]
pub struct GoogleResult {
    pub link: String,
}

impl GoogleResult {
    pub fn new(link: &str) -> Self {
        GoogleResult { link: String::from(link) }
    }
}

#[derive(Debug)]
pub struct Google {
    per_page: usize,
    client: Client,
}

impl Default for Google {
    fn default() -> Self {
        Google {
            per_page: 10,
            client: Client::new(),
        }
    }
}

impl Google {
    pub fn google(&self, query: &str) -> Vec<GoogleResult> {
        let body = self.request(query);
        self.get_links(&body)
    }

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

    fn request(&self, query: &str) -> String {
        let url = format!("https://www.google.\
                           com/search?hl=en&q={}&start=0&sa=N&num={}&ie=UTF-8&oe=UTF-8&gws_rd=ssl",
                          query,
                          self.per_page);

        let mut res = self.client
                          .get(&url)
                          .header(Connection::close())
                          .send()
                          .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        body
    }

    fn get_links(&self, body: &str) -> Vec<GoogleResult> {
        let doc = Document::from(body);

        let item_selector = And(Name("div"), Class("g"));
        let link_container_selector = And(Name("h3"), Class("r"));
        let link_selector = Name("a");
        let cleaning_regex = Regex::new(r"(/url\?q=)(?P<link>.*)&(sa=.*&?)(ved=.*&?)(usg=.*&?)")
                                 .unwrap();

        let mut results = Vec::new();

        for item in doc.find(item_selector).iter().take(self.per_page) {
            let link_container;
            match item.find(link_container_selector).first() {
                Some(container) => {
                    link_container = container;
                }
                None => {
                    continue;
                }
            };

            let link_node = link_container.find(link_selector).first().unwrap();
            let link_href = link_node.attr("href").unwrap();

            if link_href.contains("/search?q=") {
                continue;
            }

            let clean_link = cleaning_regex.captures(&link_href)
                                           .unwrap()
                                           .name("link")
                                           .unwrap();

            results.push(GoogleResult::new(&clean_link));
        }

        results
    }
}

#[test]
fn google_works() {
    let google = Google::default();
    let results = google.google("rust lang testing");

    assert_eq!(results.len(), google.per_page());
    assert!(results.iter().any(|r| r.link == "https://doc.rust-lang.org/book/testing.html"));
}
<|endoftext|>


<commit_before>use std;
use std::io::prelude::*;
use std::net::{UdpSocket, ToSocketAddrs};
use std::mem;
use std::hash::{Hash, Hasher, SipHasher};

use log::{Log, LogRecord, LogLevel, LogMetadata};
use flate2::Compression;
use flate2::write::GzEncoder;
use chrono::{DateTime, UTC};
use serde_json;
use byteorder::{BigEndian, WriteBytesExt};

use GraylogError;

const MAX_PACKET_SIZE: usize = 8192;
const MAGIC_BYTES: u16 = 0x1E0F;

struct GraylogLogger {
    server: A,
    sock: UdpSocket,
    level: LogLevel,
    hostname: String,
}

#[derive(Serialize, Deserialize)]
struct Gelf {
    version: String,
    host: String,
    short_message: String,
    full_message: Option<String>,
    timestamp: Option<i64>,
    level: Option<u8>,
}

struct GelfChunks<'a> {
    count: usize,
    total: usize,
    #[allow(dead_code)]
    data: &'a [u8],
    chunks: Vec<&'a [u8]>,
    message_id: u64,
}

struct Chunk<'a> {
    header: ChunkHeader,
    data: &'a [u8],
}

impl<'a> Chunk<'a> {
    fn to_binary(&self) -> Result<Vec<u8>, GraylogError> {
        let mut wrt = vec![];
        try!(wrt.write_u16::<BigEndian>(self.header.magic_bytes));
        try!(wrt.write_u64::<BigEndian>(self.header.message_id));
        try!(wrt.write_u8(self.header.seq_number));
        try!(wrt.write_u8(self.header.seq_count));
         wrt.extend(self.data.iter());
        Ok(wrt)
    }
}

#[derive(Debug)]
struct ChunkHeader {
    magic_bytes: u16,
    message_id: u64,
    seq_number: u8,
    seq_count: u8,
}

impl<'a> GelfChunks<'a> {
    fn new(data: &'a [u8], message_id: u64) -> GelfChunks<'a> {
        let chunk_size = MAX_PACKET_SIZE - mem::size_of::<ChunkHeader>();
        let mut chunks = data.chunks(chunk_size).collect::<Vec<&[u8]>>();
        chunks.reverse();

        GelfChunks {
            count: 0,
            total: chunks.len(),
            chunks: chunks,
            data: data,
            message_id: message_id,
        }
    }
}

impl<'a> Iterator for GelfChunks<'a> {
    type Item = Chunk<'a>;

    fn next(&mut self) -> Option<Chunk<'a>> {
        self.chunks.pop().map(|data| {
            let header = ChunkHeader {
                magic_bytes: MAGIC_BYTES,
                message_id: self.message_id,
                seq_number: self.count as u8,
                seq_count: self.total as u8,
            };
            println!("{:?}", header);

            self.count += 1;

            Chunk {
                header: header,
                data: data,
            }
        })
    }
}

pub fn init(addr: A, level: LogLevel) -> Result<(), GraylogError>
    where A: std::marker::Send + std::marker::Sync
{
    use log;
    use std::process::Command;
    let sock = try!(UdpSocket::bind("0.0.0.0:0"));

    try!(log::set_logger(|max_log_level| {
        max_log_level.set(level.to_log_level_filter());
        let hostname = Command::new("hostname")
            .arg("-f")
            .output()
            .map(|out| String::from_utf8_lossy(&out.stdout).into_owned())
            .unwrap_or("unknown".to_string());

        Box::new(GraylogLogger {
            level: level,
            server: addr,
            sock: sock,
            hostname: hostname,
        })
    }));
    Ok(())
}

impl Gelf {
    fn message_id(&self) -> u64 {
        use chrono::Timelike;
        let mut s = SipHasher::new();
        self.host.hash(&mut s);
        self.timestamp.hash(&mut s);
        UTC::now().nanosecond().hash(&mut s);
        s.finish()
    }
}

impl GraylogLogger {
    fn send_as_gelf(&self, record: &LogRecord) -> Result<usize, GraylogError> {
        let utc: DateTime<UTC> = UTC::now();

        let gelf = Gelf {
            version: "1.1".to_string(),
            short_message: format!("{}", record.args()),
            full_message: None,
            timestamp: Some(utc.timestamp()),
            level: None,
            host: self.hostname.clone(),
        };

        let json = try!(serde_json::to_string(&gelf));
        let mut e = GzEncoder::new(Vec::new(), Compression::Default);
        try!(e.write_all(json.as_bytes()));

        let compressed_bytes = try!(e.finish());
        if compressed_bytes.len() > MAX_PACKET_SIZE {
            self.send_chunked_gelf(&compressed_bytes, gelf.message_id())
        } else {
            self.send(&compressed_bytes)
        }
    }

    fn send_chunked_gelf(&self, buffer: &[u8], message_id: u64) -> Result<usize, GraylogError> {
        let chunks = GelfChunks::new(buffer, message_id);
        println!("{:x}", message_id);
        for chunk in chunks {
            let data = try!(chunk.to_binary());
            try!(self.send(&data));
        }
        Ok(1)
    }

    fn send(&self, buffer: &[u8]) -> Result<usize, GraylogError> {
        let s = try!(self.sock.send_to(buffer, &self.server).or_else(|e| {
            println!("Error writing to Graylog: {}", e);
            Err(e)
        }));
        Ok(s)
    }
}

impl Log for GraylogLogger
    where A: std::marker::Send + std::marker::Sync
{
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            if self.send_as_gelf(record).is_err() {
                println!("{} {} - {}", UTC::now(), record.level(), record.args());
            };
        }
    }
}
<commit_msg>changes the size of the chunk header size to 12<commit_after>use std;
use std::io::prelude::*;
use std::net::{UdpSocket, ToSocketAddrs};
use std::hash::{Hash, Hasher, SipHasher};

use log::{Log, LogRecord, LogLevel, LogMetadata};
use flate2::Compression;
use flate2::write::GzEncoder;
use chrono::{DateTime, UTC};
use serde_json;
use byteorder::{BigEndian, WriteBytesExt};

use GraylogError;

const MAX_PACKET_SIZE: usize = 8192;
const MAGIC_BYTES: u16 = 0x1E0F;
const HEADER_SIZE: usize = 12; // TODO: figure out how to do this with mem::size_of<ChunkHeader>()

struct GraylogLogger {
    server: A,
    sock: UdpSocket,
    level: LogLevel,
    hostname: String,
}

#[derive(Serialize, Deserialize)]
struct Gelf {
    version: String,
    host: String,
    short_message: String,
    full_message: Option<String>,
    timestamp: Option<i64>,
    level: Option<u8>,
}

struct GelfChunks<'a> {
    count: usize,
    total: usize,
    #[allow(dead_code)]
    data: &'a [u8],
    chunks: Vec<&'a [u8]>,
    message_id: u64,
}

struct Chunk<'a> {
    header: ChunkHeader,
    data: &'a [u8],
}

impl<'a> Chunk<'a> {
    fn to_binary(&self) -> Result<Vec<u8>, GraylogError> {
        let mut wrt = vec![];
        try!(wrt.write_u16::<BigEndian>(self.header.magic_bytes));
        try!(wrt.write_u64::<BigEndian>(self.header.message_id));
        try!(wrt.write_u8(self.header.seq_number));
        try!(wrt.write_u8(self.header.seq_count));
         wrt.extend(self.data.iter());
        Ok(wrt)
    }
}

#[derive(Debug)]
struct ChunkHeader {
    magic_bytes: u16,
    message_id: u64,
    seq_number: u8,
    seq_count: u8,
}

impl<'a> GelfChunks<'a> {
    fn new(data: &'a [u8], message_id: u64) -> GelfChunks<'a> {
        let chunk_size = MAX_PACKET_SIZE - HEADER_SIZE;
        let mut chunks = data.chunks(chunk_size).collect::<Vec<&[u8]>>();
        chunks.reverse();

        GelfChunks {
            count: 0,
            total: chunks.len(),
            chunks: chunks,
            data: data,
            message_id: message_id,
        }
    }
}

impl<'a> Iterator for GelfChunks<'a> {
    type Item = Chunk<'a>;

    fn next(&mut self) -> Option<Chunk<'a>> {
        self.chunks.pop().map(|data| {
            let header = ChunkHeader {
                magic_bytes: MAGIC_BYTES,
                message_id: self.message_id,
                seq_number: self.count as u8,
                seq_count: self.total as u8,
            };
            println!("{:?}", header);

            self.count += 1;

            Chunk {
                header: header,
                data: data,
            }
        })
    }
}

pub fn init(addr: A, level: LogLevel) -> Result<(), GraylogError>
    where A: std::marker::Send + std::marker::Sync
{
    use log;
    use std::process::Command;
    let sock = try!(UdpSocket::bind("0.0.0.0:0"));

    try!(log::set_logger(|max_log_level| {
        max_log_level.set(level.to_log_level_filter());
        let hostname = Command::new("hostname")
            .arg("-f")
            .output()
            .map(|out| String::from_utf8_lossy(&out.stdout).into_owned())
            .unwrap_or("unknown".to_string());

        Box::new(GraylogLogger {
            level: level,
            server: addr,
            sock: sock,
            hostname: hostname,
        })
    }));
    Ok(())
}

impl Gelf {
    fn message_id(&self) -> u64 {
        use chrono::Timelike;
        let mut s = SipHasher::new();
        self.host.hash(&mut s);
        self.timestamp.hash(&mut s);
        UTC::now().nanosecond().hash(&mut s);
        s.finish()
    }
}

impl GraylogLogger {
    fn send_as_gelf(&self, record: &LogRecord) -> Result<usize, GraylogError> {
        let utc: DateTime<UTC> = UTC::now();

        let gelf = Gelf {
            version: "1.1".to_string(),
            short_message: format!("{}", record.args()),
            full_message: None,
            timestamp: Some(utc.timestamp()),
            level: None,
            host: self.hostname.clone(),
        };

        let json = try!(serde_json::to_string(&gelf));
        let mut e = GzEncoder::new(Vec::new(), Compression::Default);
        try!(e.write_all(json.as_bytes()));

        let compressed_bytes = try!(e.finish());
        if compressed_bytes.len() > MAX_PACKET_SIZE {
            self.send_chunked_gelf(&compressed_bytes, gelf.message_id())
        } else {
            self.send(&compressed_bytes)
        }
    }

    fn send_chunked_gelf(&self, buffer: &[u8], message_id: u64) -> Result<usize, GraylogError> {
        let chunks = GelfChunks::new(buffer, message_id);
        println!("Graylog message_id: {:x}", message_id);
        for chunk in chunks {
            let data = try!(chunk.to_binary());
            try!(self.send(&data));
        }
        Ok(1)
    }

    fn send(&self, buffer: &[u8]) -> Result<usize, GraylogError> {
        let s = try!(self.sock.send_to(buffer, &self.server).or_else(|e| {
            println!("Error writing to Graylog: {}", e);
            Err(e)
        }));
        Ok(s)
    }
}

impl Log for GraylogLogger
    where A: std::marker::Send + std::marker::Sync
{
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            if self.send_as_gelf(record).is_err() {
                println!("{} {} - {}", UTC::now(), record.level(), record.args());
            };
        }
    }
}
<|endoftext|>


<commit_before>use crate::error::Error;
use crate::nameserver::NameServerConfig;
use crate::resolver::Resolver;
use crate::resources::Record;
use crate::serialize::ser_arc_nameserver_config;
use crate::{MultiQuery, Query};
use chrono::{DateTime, Duration, Utc};
use futures::stream::{self, StreamExt};
use log::{debug, trace};
use serde::Serialize;
use std::sync::Arc;
use std::time::Instant;
use trust_dns_resolver::error::{ResolveError, ResolveErrorKind};
use trust_dns_resolver::proto::xfer::DnsRequestOptions;

#[derive(Debug, Clone, Serialize)]
pub struct LookupResult {
    query: Query,
    #[serde(serialize_with = "ser_arc_nameserver_config")]
    name_server: Arc<NameServerConfig>,
    result: Lookup,
}

impl LookupResult {
    pub async fn lookup(resolver: Resolver, query: Query) -> LookupResult {
        do_lookup(&resolver, query).await
    }

    pub async fn multi_lookups(resolver: Resolver, multi_query: MultiQuery) -> Vec<LookupResult> {
        let MultiQuery { name, record_types } = multi_query;
        let lookups: Vec<_> = record_types
            .into_iter()
            .map(|record_type| Query {
                name: name.clone(),
                record_type,
            })
            .map(|q| do_lookup(&resolver, q))
            .collect();

        stream::iter(lookups)
            .buffer_unordered(resolver.opts.max_concurrent_requests)
            .inspect(|lookup| trace!("Received lookup {:?}", lookup))
            .collect::<Vec<LookupResult>>()
            .await
    }

    pub fn query(&self) -> &Query {
        &self.query
    }

    pub fn name_server(&self) -> &NameServerConfig {
        &self.name_server
    }

    pub fn result(&self) -> &Lookup {
        &self.result
    }
}

#[derive(Debug, Clone, Serialize)]
pub enum Lookup {
    Lookup {
        records: Vec<Record>,
        valid_until: DateTime<Utc>,
    },
    NxDomain {
        valid_until: Option<DateTime<Utc>>,
    },
    Timeout,
    Error(String),
}

impl Lookup {
    pub fn is_ok(&self) -> bool {
        match self {
            Lookup::Lookup { .. } => true,
            _ => false,
        }
    }
}

#[doc(hidden)]
impl From<std::result::Result<trust_dns_resolver::lookup::Lookup, ResolveError>> for Lookup {
    fn from(res: std::result::Result<trust_dns_resolver::lookup::Lookup, ResolveError>) -> Self {
        match res {
            Ok(lookup) => {
                let records: Vec<Record> = lookup.record_iter().map(Record::from).collect();
                Lookup::Lookup {
                    records,
                    valid_until: instant_to_utc(lookup.valid_until()),
                }
            }
            Err(err) => match err.kind() {
                ResolveErrorKind::NoRecordsFound { valid_until, .. } => Lookup::NxDomain {
                    valid_until: valid_until.map(instant_to_utc),
                },
                ResolveErrorKind::Timeout => Lookup::Timeout,
                _ => Lookup::Error(Error::from(err).to_string()),
            },
        }
    }
}

async fn do_lookup(resolver: &Resolver, query: Query) -> LookupResult {
    let q = query.clone();
    let result = resolver
        .inner
        .lookup(q.name, q.record_type.into(), DnsRequestOptions::default())
        .await
        .into();
    debug!(
        "Received Lookup for '{}', record type {} from {:?}.",
        &query.name,
        &query.record_type,
        resolver.name()
    );

    LookupResult {
        query,
        name_server: resolver.name_server.clone(),
        result,
    }
}

fn instant_to_utc(instant: Instant) -> DateTime<Utc> {
    let now = Instant::now();
    let duration = instant.duration_since(now);

    Utc::now() + Duration::from_std(duration).unwrap() // Safe, because I know this is a valid duration
}
<commit_msg>Add response time to Lookup<commit_after>use crate::error::Error;
use crate::nameserver::NameServerConfig;
use crate::resolver::Resolver;
use crate::resources::Record;
use crate::serialize::ser_arc_nameserver_config;
use crate::{MultiQuery, Query};
use chrono::{DateTime, Utc};
use futures::stream::{self, StreamExt};
use log::{debug, trace};
use serde::Serialize;
use std::sync::Arc;
use std::time::{Instant, Duration};
use trust_dns_resolver::error::{ResolveError, ResolveErrorKind};
use trust_dns_resolver::proto::xfer::DnsRequestOptions;

#[derive(Debug, Clone, Serialize)]
pub struct LookupResult {
    query: Query,
    #[serde(serialize_with = "ser_arc_nameserver_config")]
    name_server: Arc<NameServerConfig>,
    result: Lookup,
}

impl LookupResult {
    pub async fn lookup(resolver: Resolver, query: Query) -> LookupResult {
        do_lookup(&resolver, query).await
    }

    pub async fn multi_lookups(resolver: Resolver, multi_query: MultiQuery) -> Vec<LookupResult> {
        let MultiQuery { name, record_types } = multi_query;
        let lookups: Vec<_> = record_types
            .into_iter()
            .map(|record_type| Query {
                name: name.clone(),
                record_type,
            })
            .map(|q| do_lookup(&resolver, q))
            .collect();

        stream::iter(lookups)
            .buffer_unordered(resolver.opts.max_concurrent_requests)
            .inspect(|lookup| trace!("Received lookup {:?}", lookup))
            .collect::<Vec<LookupResult>>()
            .await
    }

    pub fn query(&self) -> &Query {
        &self.query
    }

    pub fn name_server(&self) -> &NameServerConfig {
        &self.name_server
    }

    pub fn result(&self) -> &Lookup {
        &self.result
    }
}

#[derive(Debug, Clone, Serialize)]
pub enum Lookup {
    Lookup {
        records: Vec<Record>,
        response_time: Duration,
        valid_until: DateTime<Utc>,
    },
    NxDomain {
        response_time: Duration,
        valid_until: Option<DateTime<Utc>>,
    },
    Timeout,
    Error(String),
}

impl Lookup {
    pub fn is_ok(&self) -> bool {
        match self {
            Lookup::Lookup { .. } => true,
            _ => false,
        }
    }
}

async fn do_lookup(resolver: &Resolver, query: Query) -> LookupResult {
    let q = query.clone();
    let start_time = Instant::now();
    let result = resolver
        .inner
        .lookup(q.name, q.record_type.into(), DnsRequestOptions::default())
        .await
        .into_lookup(start_time);
    debug!(
        "Received Lookup for '{}', record type {} from {:?}.",
        &query.name,
        &query.record_type,
        resolver.name()
    );

    LookupResult {
        query,
        name_server: resolver.name_server.clone(),
        result,
    }
}

#[doc(hidden)]
trait IntoLookup {
    fn into_lookup(self, start_time: Instant) -> Lookup;
}

#[doc(hidden)]
impl IntoLookup for std::result::Result<trust_dns_resolver::lookup::Lookup, ResolveError> {
    fn into_lookup(self, start_time: Instant) -> Lookup {
        match self {
            Ok(lookup) => {
                let records: Vec<Record> = lookup.record_iter().map(Record::from).collect();
                Lookup::Lookup {
                    records,
                    response_time: Instant::now() - start_time,
                    valid_until: instant_to_utc(lookup.valid_until()),
                }
            }
            Err(err) => match err.kind() {
                ResolveErrorKind::NoRecordsFound { valid_until, .. } => Lookup::NxDomain {
                    response_time: Instant::now() - start_time,
                    valid_until: valid_until.map(instant_to_utc),
                },
                ResolveErrorKind::Timeout => Lookup::Timeout,
                _ => Lookup::Error(Error::from(err).to_string()),
            },
        }
    }
}

fn instant_to_utc(instant: Instant) -> DateTime<Utc> {
    let now = Instant::now();
    let duration = instant.duration_since(now);

    Utc::now() + chrono::Duration::from_std(duration).unwrap() // Safe, because I know this is a valid duration
}
<|endoftext|>


<commit_before>#[macro_export]

macro_rules! enum_to_nl {
    ( $name:ident, $type:tt, $( $cmd:ident ),* ) => {
        #[derive(Clone,Debug,PartialEq)]
        pub enum $name {
            $( $cmd, )*
            UnrecognizedVariant,
        }

        impl Into<$type> for $name {
            fn into(self) -> $type {
                self as $type
            }
        }

        impl From<$type> for $name {
            fn from(v: $type) -> Self {
                match v {
                    $(
                        i if i == $name::$cmd as $type => $name::$cmd,
                    )*
                    _ => $name::UnrecognizedVariant,
                }
            }
        }

        impl Nl for $name {
            type SerIn = ();
            type DeIn = ();

            fn serialize(&self, mem: &mut MemWrite) -> Result<(), SerError> {
                let val = self.clone() as $type;
                val.serialize(mem)?;
                Ok(())
            }

            fn deserialize(mem: &mut MemRead) -> Result<Self, DeError> {
                let cmd = $type::deserialize(mem)?;
                Ok(Self::from(cmd))
            }

            fn size(&self) -> usize {
                ::std::mem::size_of::<$type>()
            }
        }
    }
}

#[macro_export]
macro_rules! cmd_to_nl {
    ( $name:ident, $( $cmd:ident ),* ) => {
        enum_to_nl!($name, u8, $( $cmd ),*);
    }
}

#[cfg(test)]
mod test {
    use {Nl,MemRead,MemWrite};
    use err::{SerError,DeError};

    #[test]
    fn test_attr_cmd_to_nl_macro() {
        cmd_to_nl!(TestCmd, Cmd0, Cmd1, Cmd2, Cmd3);

        let slice = &mut [0u8; 1];
        let mut ser_mem = MemWrite::new_slice(slice);
        TestCmd::Cmd1.serialize(&mut ser_mem).unwrap();
        assert_eq!(ser_mem.as_slice(), &[1]);
        let mut de_mem = ser_mem.into();
        assert_eq!(TestCmd::Cmd1, TestCmd::deserialize(&mut de_mem).unwrap());
    }
}
<commit_msg>Rework macros to allow choosing relevant enum options<commit_after>#[macro_export]

macro_rules! enum_to_nl {
    ( $name:ident, $type:tt, $( $cmd:ident ),* ) => {
        #[derive(Clone,Debug,PartialEq)]
        pub enum $name {
            $( $cmd, )*
            UnrecognizedVariant,
        }

        impl Into<$type> for $name {
            fn into(self) -> $type {
                self as $type
            }
        }

        impl From<$type> for $name {
            fn from(v: $type) -> Self {
                match v {
                    $(
                        i if i == $name::$cmd as $type => $name::$cmd,
                    )*
                    _ => $name::UnrecognizedVariant,
                }
            }
        }

        impl Nl for $name {
            type SerIn = ();
            type DeIn = ();

            fn serialize(&self, mem: &mut MemWrite) -> Result<(), SerError> {
                let val = self.clone() as $type;
                val.serialize(mem)?;
                Ok(())
            }

            fn deserialize(mem: &mut MemRead) -> Result<Self, DeError> {
                let cmd = $type::deserialize(mem)?;
                Ok(Self::from(cmd))
            }

            fn size(&self) -> usize {
                ::std::mem::size_of::<$type>()
            }
        }
    };
    ( $name:ident, $type:tt, $( $cmd:ident = $num:tt ),* ) => {
        #[derive(Clone,Debug,PartialEq)]
        pub enum $name {
            $( $cmd = $num, )*
            UnrecognizedVariant,
        }

        impl Into<$type> for $name {
            fn into(self) -> $type {
                self as $type
            }
        }

        impl From<$type> for $name {
            fn from(v: $type) -> Self {
                match v {
                    $(
                        i if i == $name::$cmd as $type => $name::$cmd,
                    )*
                    _ => $name::UnrecognizedVariant,
                }
            }
        }

        impl Nl for $name {
            type SerIn = ();
            type DeIn = ();

            fn serialize(&self, mem: &mut MemWrite) -> Result<(), SerError> {
                let val = self.clone() as $type;
                val.serialize(mem)?;
                Ok(())
            }

            fn deserialize(mem: &mut MemRead) -> Result<Self, DeError> {
                let cmd = $type::deserialize(mem)?;
                Ok(Self::from(cmd))
            }

            fn size(&self) -> usize {
                ::std::mem::size_of::<$type>()
            }
        }
    };
}

#[macro_export]
macro_rules! cmd_to_nl {
    ( $name:ident, $( $cmd:ident ),* ) => {
        enum_to_nl!($name, u8, $( $cmd ),*);
    };
    ( $name:ident, $( $cmd:ident = $num:tt ),* ) => {
        enum_to_nl!($name, u8, $( $cmd = $num ),*);
    };
}

#[cfg(test)]
mod test {
    use {Nl,MemRead,MemWrite};
    use err::{SerError,DeError};

    #[test]
    fn test_attr_cmd_to_nl_macro() {
        cmd_to_nl!(TestCmd, Cmd0, Cmd1, Cmd2, Cmd3);

        let slice = &mut [0u8; 1];
        let mut ser_mem = MemWrite::new_slice(slice);
        TestCmd::Cmd1.serialize(&mut ser_mem).unwrap();
        assert_eq!(ser_mem.as_slice(), &[1]);
        let mut de_mem = ser_mem.into();
        assert_eq!(TestCmd::Cmd1, TestCmd::deserialize(&mut de_mem).unwrap());
    }
}
<|endoftext|>


<commit_before>#![macro_use]

#[macro_export]
macro_rules! clip {
    ($lb:expr, $x:expr, $ub:expr) => {
        {
            $lb.max($ub.min($x))
        }
    }
}
<commit_msg>Internalise the clip macro<commit_after>#![macro_use]

macro_rules! clip {
    ($lb:expr, $x:expr, $ub:expr) => {
        {
            $lb.max($ub.min($x))
        }
    }
}
<|endoftext|>


<commit_before>//! Aperture Macros.

use ::{GerberCode, GerberResult};

#[derive(Debug)]
pub struct ApertureMacro {
    pub name: String,
}

#[derive(Debug)]
pub enum Primitive {
    Comment(String),
    Circle(CirclePrimitive),
    VectorLine(VectorLinePrimitive),
    CenterLine(CenterLinePrimitive),
}

impl GerberCode for Primitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = match *self {
            Primitive::Comment(ref s) => s.clone(),
            Primitive::Circle(ref c) => try!(c.to_code()),
            Primitive::VectorLine(ref vl) => try!(vl.to_code()),
            Primitive::CenterLine(ref cl) => try!(cl.to_code()),
        };
        Ok(code)
    }
}

#[derive(Debug)]
pub struct CirclePrimitive {
    /// Exposure off/on
    pub exposure: bool,

    /// Diameter, a decimal >= 0
    pub diameter: f64,

    /// X and Y coordinates of center position, decimals
    pub center: (f64, f64),

    /// Rotation angle.
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    ///
    /// The rotation modifier is optional. The default is no rotation. (We
    /// recommend always to set the angle explicitly.
    pub angle: Option<f64>,
}

impl GerberCode for CirclePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let mut code = "1,".to_string();
        code.push_str(&try!(self.exposure.to_code()));
        code.push_str(&format!(",{},{},{}", self.diameter, self.center.0, self.center.1));
        if let Some(a) = self.angle {
            code.push_str(&format!(",{}", a));
        }
        Ok(code)
    }
}

#[derive(Debug)]
pub struct VectorLinePrimitive {
    /// Exposure off/on
    pub exposure: bool,

    /// Line width, a decimal >= 0
    pub width: f64,

    /// X and Y coordinates of start point, decimals
    pub start: (f64, f64),

    /// X and Y coordinates of end point, decimals
    pub end: (f64, f64),

    /// Rotation angle of the vector line primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    pub angle: f64,
}

impl GerberCode for VectorLinePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = format!(
            "20,{},{},{},{},{},{},{}",
            try!(self.exposure.to_code()),
            self.width,
            self.start.0, self.start.1, self.end.0, self.end.1,
            self.angle
        );
        Ok(code)
    }
}

#[derive(Debug)]
pub struct CenterLinePrimitive {
    /// Exposure off/on (0/1)
    pub exposure: bool,

    /// Rectangle dimensions (width/height)
    pub dimensions: (f64, f64),

    /// X and Y coordinates of center point, decimals
    pub center: (f64, f64),

    /// Rotation angle
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. (0, 0) point
    /// of macro coordinates.
    pub angle: f64,
}

impl GerberCode for CenterLinePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = format!(
            "21,{},{},{},{},{},{}",
            try!(self.exposure.to_code()),
            self.dimensions.0, self.dimensions.1,
            self.center.0, self.center.1,
            self.angle
        );
        Ok(code)
    }
}

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

    #[test]
    fn test_circle_primitive_codegen() {
        let with_angle = CirclePrimitive {
            exposure: true,
            diameter: 1.5,
            center: (0., 0.),
            angle: Some(0.),
        };
        assert_eq!(with_angle.to_code().unwrap(), "1,1,1.5,0,0,0".to_string());
        let no_angle = CirclePrimitive {
            exposure: false,
            diameter: 99.9,
            center: (1.1, 2.2),
            angle: None,
        };
        assert_eq!(no_angle.to_code().unwrap(), "1,0,99.9,1.1,2.2".to_string());
    }

    #[test]
    fn test_vector_line_primitive_codegen() {
        let line = VectorLinePrimitive {
            exposure: true,
            width: 0.9,
            start: (0., 0.45),
            end: (12., 0.45),
            angle: 0.,
        };
        assert_eq!(line.to_code().unwrap(), "20,1,0.9,0,0.45,12,0.45,0".to_string());
    }

    #[test]
    fn test_center_line_primitive_codegen() {
        let line = CenterLinePrimitive {
            exposure: true,
            dimensions: (6.8, 1.2),
            center: (3.4, 0.6),
            angle: 30.0,
        };
        assert_eq!(line.to_code().unwrap(), "21,1,6.8,1.2,3.4,0.6,30".to_string());
    }
}
<commit_msg>Add missing trailing asterisk to primitives<commit_after>//! Aperture Macros.

use ::{GerberCode, GerberResult};

#[derive(Debug)]
pub struct ApertureMacro {
    pub name: String,
}

#[derive(Debug)]
pub enum Primitive {
    Comment(String),
    Circle(CirclePrimitive),
    VectorLine(VectorLinePrimitive),
    CenterLine(CenterLinePrimitive),
}

impl GerberCode for Primitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = match *self {
            Primitive::Comment(ref s) => s.clone(),
            Primitive::Circle(ref c) => try!(c.to_code()),
            Primitive::VectorLine(ref vl) => try!(vl.to_code()),
            Primitive::CenterLine(ref cl) => try!(cl.to_code()),
        };
        Ok(code)
    }
}

#[derive(Debug)]
pub struct CirclePrimitive {
    /// Exposure off/on
    pub exposure: bool,

    /// Diameter, a decimal >= 0
    pub diameter: f64,

    /// X and Y coordinates of center position, decimals
    pub center: (f64, f64),

    /// Rotation angle.
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    ///
    /// The rotation modifier is optional. The default is no rotation. (We
    /// recommend always to set the angle explicitly.
    pub angle: Option<f64>,
}

impl GerberCode for CirclePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let mut code = "1,".to_string();
        code.push_str(&try!(self.exposure.to_code()));
        code.push_str(&format!(",{},{},{}", self.diameter, self.center.0, self.center.1));
        if let Some(a) = self.angle {
            code.push_str(&format!(",{}", a));
        }
        code.push_str("*");
        Ok(code)
    }
}

#[derive(Debug)]
pub struct VectorLinePrimitive {
    /// Exposure off/on
    pub exposure: bool,

    /// Line width, a decimal >= 0
    pub width: f64,

    /// X and Y coordinates of start point, decimals
    pub start: (f64, f64),

    /// X and Y coordinates of end point, decimals
    pub end: (f64, f64),

    /// Rotation angle of the vector line primitive
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. the (0, 0)
    /// point of macro coordinates.
    pub angle: f64,
}

impl GerberCode for VectorLinePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = format!(
            "20,{},{},{},{},{},{},{}*",
            try!(self.exposure.to_code()),
            self.width,
            self.start.0, self.start.1, self.end.0, self.end.1,
            self.angle
        );
        Ok(code)
    }
}

#[derive(Debug)]
pub struct CenterLinePrimitive {
    /// Exposure off/on (0/1)
    pub exposure: bool,

    /// Rectangle dimensions (width/height)
    pub dimensions: (f64, f64),

    /// X and Y coordinates of center point, decimals
    pub center: (f64, f64),

    /// Rotation angle
    ///
    /// The rotation angle is specified by a decimal, in degrees. The primitive
    /// is rotated around the origin of the macro definition, i.e. (0, 0) point
    /// of macro coordinates.
    pub angle: f64,
}

impl GerberCode for CenterLinePrimitive {
    fn to_code(&self) -> GerberResult<String> {
        let code = format!(
            "21,{},{},{},{},{},{}*",
            try!(self.exposure.to_code()),
            self.dimensions.0, self.dimensions.1,
            self.center.0, self.center.1,
            self.angle
        );
        Ok(code)
    }
}

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

    #[test]
    fn test_circle_primitive_codegen() {
        let with_angle = CirclePrimitive {
            exposure: true,
            diameter: 1.5,
            center: (0., 0.),
            angle: Some(0.),
        };
        assert_eq!(with_angle.to_code().unwrap(), "1,1,1.5,0,0,0*".to_string());
        let no_angle = CirclePrimitive {
            exposure: false,
            diameter: 99.9,
            center: (1.1, 2.2),
            angle: None,
        };
        assert_eq!(no_angle.to_code().unwrap(), "1,0,99.9,1.1,2.2*".to_string());
    }

    #[test]
    fn test_vector_line_primitive_codegen() {
        let line = VectorLinePrimitive {
            exposure: true,
            width: 0.9,
            start: (0., 0.45),
            end: (12., 0.45),
            angle: 0.,
        };
        assert_eq!(line.to_code().unwrap(), "20,1,0.9,0,0.45,12,0.45,0*".to_string());
    }

    #[test]
    fn test_center_line_primitive_codegen() {
        let line = CenterLinePrimitive {
            exposure: true,
            dimensions: (6.8, 1.2),
            center: (3.4, 0.6),
            angle: 30.0,
        };
        assert_eq!(line.to_code().unwrap(), "21,1,6.8,1.2,3.4,0.6,30*".to_string());
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/// Connect events to sending a message.
///
/// ## Rules
/// 1. Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// 3. Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// 4. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// ## Rules
/// 1. Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}

/// Connect an asynchronous method call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = $relm.stream().clone();
        $object.$async_method($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $object.$async_method($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });
    }};
}

/// Connect an asynchronous function call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async_func {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = $relm.stream().clone();
        $class::$async_func($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $class::$async_func($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });

    }};
}

/// Like `connect_async!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_full {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = $relm.stream().clone();
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
        cancellable
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}

/// Like `connect_async_func!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_func_full {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async!($async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = $relm.stream().clone();
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.emit($msg(result));
            }
        });
        cancellable
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = $relm.stream().clone();
        let fail_event_stream = $relm.stream().clone();
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.emit($msg(value)),
                Err(error) => fail_event_stream.emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}
<commit_msg>Revert "Temporary fix to publish the crate"<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

include!("../relm-state/src/macros.rs");
<|endoftext|>