<commit_before>extern crate libc;

use unique::Unique;
use std::ptr::{self};
use std::ffi::{CStr,CString};
use std::default::Default;
use std::path::Path;
use std::slice;
use std::ops::Deref;
use std::str;
use std::fmt;
use std::convert::From;
mod raw;
mod unique;

use self::Error::*;

const PCAP_ERROR_NOT_ACTIVATED: i32 = -3;

/// An error received from pcap
#[derive(Debug)]
pub enum Error {
    MalformedError(str::Utf8Error),
    PcapError(String)
}

impl Error {
    fn new<T>(ptr: *const libc::c_char) -> Result<T, Error> {
        Err(PcapError(try!(cstr_to_string(ptr))))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MalformedError(e) => {
                write!(f, "pcap returned an error that was not encoded properly: {}", e)
            },
            PcapError(ref e) => {
                write!(f, "pcap error: {}", e)
            }
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            MalformedError(..) => "error message from pcap is invalid",
            PcapError(..) => "pcap FFI error"
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            MalformedError(ref e) => Some(e),
            _ => None
        }
    }
}

impl From<str::Utf8Error> for Error {
    fn from(obj: str::Utf8Error) -> Error {
        MalformedError(obj)
    }
}

/// An iterator over devices that pcap is aware about on the system.
pub struct Devices {
    orig: Unique<raw::Struct_pcap_if>,
    device: Unique<raw::Struct_pcap_if>
}

impl Devices {
    /// Construct a new `Devices` iterator by internally using `pcap_findalldevs()`
    pub fn list_all() -> Result<Devices, Error> {
        unsafe {
            let mut errbuf = [0i8; 256];
            let mut dev_buf: *mut raw::Struct_pcap_if = ptr::null_mut();

            match raw::pcap_findalldevs(&mut dev_buf, errbuf.as_mut_ptr()) {
                0 => {
                    Ok(Devices {
                        orig: Unique::new(dev_buf),
                        device: Unique::new(dev_buf)
                    })
                },
                _ => {
                    Error::new(errbuf.as_ptr())
                }
            }
        }
    }
}

impl Iterator for Devices {
    type Item = Device;

    fn next(&mut self) -> Option<Device> {
        if self.device.is_null() {
            None
        } else {
            unsafe {
                let ret = Device {
                    name: cstr_to_string(self.device.get().name).unwrap(),
                    desc: {
                        if !self.device.get().description.is_null() {
                            Some(cstr_to_string(self.device.get().description).unwrap())
                        } else {
                            None
                        }
                    }
                };
                self.device = Unique::new(self.device.get().next);

                Some(ret)
            }
        }
    }
}

impl Drop for Devices {
    fn drop(&mut self) {
        unsafe {
            raw::pcap_freealldevs(*self.orig);
        }
    }
}

#[derive(Debug)]
/// A network device as returned from `Devices::list_all()`.
pub struct Device {
    pub name: String,
    pub desc: Option<String>
}

impl Device {
    /// Returns the default Device suitable for captures according to pcap_lookupdev,
    /// or an error from pcap.
    pub fn lookup() -> Result<Device, Error> {
        let mut errbuf = [0i8; 256];

        unsafe {
            let default_name = raw::pcap_lookupdev(errbuf.as_mut_ptr());

            if default_name.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            Ok(Device {
                name: try!(cstr_to_string(default_name)),
                desc: None
            })
        }
    }
}

impl<'a> Into<Device> for &'a str {
    fn into(self) -> Device {
        Device {
            name: self.into(),
            desc: None
        }
    }
}

/// This is a datalink link type returned from pcap.
#[derive(Debug)]
pub struct Linktype(pub i32);

impl Linktype {
    /// Gets the name of the link type, such as EN10MB
    pub fn get_name(&self) -> Result<String, Error> {
        unsafe {
            Ok(try!(cstr_to_string(raw::pcap_datalink_val_to_name(self.0))))
        }
    }

    /// Gets the description of a link type.
    pub fn get_description(&self) -> Result<String, Error> {
        unsafe {
            Ok(try!(cstr_to_string(raw::pcap_datalink_val_to_description(self.0))))
        }
    }
}

/// This is a builder for a `Capture` handle. It's useful when you want to specify certain
/// parameters, like promiscuous mode, or buffer length, before opening.
///
/// You can use `Capture::from_device()` instead of this builder, with less flexibility.
pub struct CaptureBuilder {
    buffer_size: i32,
    snaplen: i32,
    promisc: i32,
    rfmon: Option<i32>,
    timeout: i32,
}

impl CaptureBuilder {
    /// Creates a `CaptureBuilder` with sensible defaults.
    pub fn new() -> CaptureBuilder {
        CaptureBuilder {
            buffer_size: 1000000,
            snaplen: 65535,
            promisc: 0,
            rfmon: None,
            timeout: 0
        }
    }

    /// Open a `Capture` with this `CaptureBuilder` with the given device. You can
    /// provide a `Device` or an &str name of the device/source you would like to open.
    pub fn open<D: Into<Device>>(&self, device: D) -> Result<Capture, Error> {
        let device: Device = device.into();
        let name = CString::new(device.name).unwrap();
        // TODO: handle errors better throughout this library
        let mut errbuf = [0i8; 256];

        unsafe {
            let handle = raw::pcap_create(name.as_ptr(), errbuf.as_mut_ptr());
            if handle.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            let cap = Capture {
                handle: Unique::new(handle)
            };

            raw::pcap_set_snaplen(handle, self.snaplen);
            raw::pcap_set_buffer_size(handle, self.buffer_size);
            raw::pcap_set_promisc(handle, self.promisc);
            match self.rfmon {
                Some(rfmon) => {
                    raw::pcap_set_rfmon(handle, rfmon);
                },
                None => {}
            };
            raw::pcap_set_timeout(handle, self.timeout);

            if 0 != raw::pcap_activate(handle) {
                return Error::new(raw::pcap_geterr(handle));
            }

            Ok(cap)
        }
    }

    /// Set the read timeout for the Capture. By default, this is 0, so it will block
    /// indefinitely.
    pub fn timeout(&mut self, ms: i32) -> &mut CaptureBuilder {
        self.timeout = ms;
        self
    }

    /// Set promiscuous mode on or off. By default, this is off.
    pub fn promisc(&mut self, to: bool) -> &mut CaptureBuilder {
        self.promisc = if to {1} else {0};
        self
    }

    /// Set rfmon mode on or off. The default is maintained by pcap.
    pub fn rfmon(&mut self, to: bool) -> &mut CaptureBuilder {
        self.rfmon = Some(if to {1} else {0});
        self
    }

    /// Set the buffer size for incoming packet data.
    ///
    /// The default is 1000000. This should always be larger than the snaplen.
    pub fn buffer_size(&mut self, to: i32) -> &mut CaptureBuilder {
        self.buffer_size = to;
        self
    }

    /// Set the snaplen size (the maximum length of a packet captured into the buffer).
    /// Useful if you only want certain headers, but not the entire packet.
    ///
    /// The default is 65535
    pub fn snaplen(&mut self, to: i32) -> &mut CaptureBuilder {
        self.snaplen = to;
        self
    }
}

/// Represents a packet returned from pcap. This can be dereferenced to access
/// the underlying packet `[u8]` slice.
pub struct Packet<'a> {
    header: &'a raw::Struct_pcap_pkthdr,
    data: &'a libc::c_uchar
}

impl<'b> Deref for Packet<'b> {
    type Target = [u8];

    fn deref<'a>(&'a self) -> &'a [u8] {
        unsafe {
            slice::from_raw_parts(self.data, self.header.caplen as usize)
        }
    }
}

impl<'a> std::fmt::Debug for Packet<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        self.deref().fmt(f)
    }
}

/// This represents an open capture handle attached to a device or file.
///
/// Internally it represents a `pcap_t`.
pub struct Capture {
    handle: Unique<raw::pcap_t>
}

impl Capture {
    /// Creates a capture handle from the specified device, or an error from pcap.
    ///
    /// You can provide this a `Device` from `Devices::list_all()` or an `&str` name of
    /// the device such as "any" on Linux.
    pub fn from_device<D: Into<Device>>(device: D) -> Result<Capture, Error> {
        CaptureBuilder::new().open(device)
    }

    /// Creates a capture handle from the specified file, or an error from pcap.
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Capture, Error> {
        let name = CString::new(path.as_ref().to_str().unwrap()).unwrap();
        let mut errbuf = [0i8; 256];

        unsafe {
            let handle = raw::pcap_open_offline(name.as_ptr(), errbuf.as_mut_ptr());
            if handle.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            let cap = Capture {
                handle: Unique::new(handle)
            };

            Ok(cap)
        }
    }

    /// List the datalink types that this captured device supports.
    pub fn list_datalinks(&mut self) -> Result<Vec<Linktype>, Error> {
        unsafe {
            let mut links: *mut i32 = ptr::null_mut();

            let num = raw::pcap_list_datalinks(*self.handle, &mut links);

            if num == PCAP_ERROR_NOT_ACTIVATED {
                raw::pcap_free_datalinks(links);
                panic!("It should not be possible to run list_datalinks on a Capture that is not activated, please report this bug!")
            } else if num < 0 {
                raw::pcap_free_datalinks(links);
                Error::new(raw::pcap_geterr(*self.handle))
            } else {
                let slice = slice::from_raw_parts(links, num as usize).iter().map(|&a| Linktype(a)).collect();
                raw::pcap_free_datalinks(links);

                Ok(slice)
            }
        }
    }

    /// Set the datalink type for the current capture handle.
    pub fn set_datalink(&mut self, linktype: Linktype) -> Result<(), Error> {
        unsafe {
            match raw::pcap_set_datalink(*self.handle, linktype.0) {
                0 => {
                    Ok(())
                },
                _ => {
                    Error::new(raw::pcap_geterr(*self.handle))
                }
            }
        }
    }

    /// Get the current datalink type for this capture handle.
    pub fn get_datalink(&mut self) -> Linktype {
        unsafe {
            match raw::pcap_datalink(*self.handle) {
                PCAP_ERROR_NOT_ACTIVATED => {
                    panic!("It should not be possible to run get_datalink on a Capture that is not activated, please report this bug!");
                },
                lt => {
                    Linktype(lt)
                }
            }
        }
    }

    /// Blocks until a packet is returned from the capture handle or an error occurs.
    ///
    /// pcap captures packets and places them into a buffer which this function reads
    /// from. This buffer has a finite length, so if the buffer fills completely new
    /// packets will be discarded temporarily. This means that in realtime situations,
    /// you probably want to minimize the time between calls of this next() method.
    pub fn next<'a>(&'a mut self) -> Option<Packet<'a>> {
        unsafe {
            let mut header: *mut raw::Struct_pcap_pkthdr = ptr::null_mut();
            let mut packet: *const libc::c_uchar = ptr::null();
            match raw::pcap_next_ex(*self.handle, &mut header, &mut packet) {
                1 => {
                    // packet was read without issue
                    Some(Packet {
                        header: &*header,
                        data: &*packet
                    })
                },
                _ => {
                    None
                }
            }
        }
    }

    /// Adds a filter to the capture using the given BPF program string. Internally
    /// this is compiled using `pcap_compile()`.
    ///
    /// See http://biot.com/capstats/bpf.html for more information about this syntax.
    pub fn filter(&mut self, program: &str) -> Result<(), Error> {
        let program = CString::new(program).unwrap();

        unsafe {
            let mut bpf_program: raw::Struct_bpf_program = Default::default();

            if -1 == raw::pcap_compile(*self.handle, &mut bpf_program, program.as_ptr(), 0, 0) {
                return Error::new(raw::pcap_geterr(*self.handle));
            }

            if -1 == raw::pcap_setfilter(*self.handle, &mut bpf_program) {
                raw::pcap_freecode(&mut bpf_program);
                return Error::new(raw::pcap_geterr(*self.handle));
            }

            raw::pcap_freecode(&mut bpf_program);
            Ok(())
        }
    }
}

impl Drop for Capture {
    fn drop(&mut self) {
        unsafe {
            raw::pcap_close(*self.handle)
        }
    }
}

fn cstr_to_string(ptr: *const libc::c_char) -> Result<String, str::Utf8Error> {
    Ok(try!(str::from_utf8(unsafe{CStr::from_ptr(ptr)}.to_bytes())).to_string())
}
<commit_msg>Cleanup<commit_after>extern crate libc;

use unique::Unique;
use std::ptr::{self};
use std::ffi::{CStr,CString};
use std::path::Path;
use std::slice;
use std::ops::Deref;
use std::str;
use std::fmt;
use self::Error::*;

mod raw;
mod unique;

const PCAP_ERROR_NOT_ACTIVATED: i32 = -3;

/// An error received from pcap
#[derive(Debug)]
pub enum Error {
    MalformedError(str::Utf8Error),
    PcapError(String)
}

impl Error {
    fn new<T>(ptr: *const libc::c_char) -> Result<T, Error> {
        Err(PcapError(try!(cstr_to_string(ptr))))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MalformedError(e) => {
                write!(f, "pcap returned an error that was not encoded properly: {}", e)
            },
            PcapError(ref e) => {
                write!(f, "pcap error: {}", e)
            }
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            MalformedError(..) => "error message from pcap is invalid",
            PcapError(..) => "pcap FFI error"
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            MalformedError(ref e) => Some(e),
            _ => None
        }
    }
}

impl From<str::Utf8Error> for Error {
    fn from(obj: str::Utf8Error) -> Error {
        MalformedError(obj)
    }
}

/// An iterator over devices that pcap is aware about on the system.
pub struct Devices {
    orig: Unique<raw::Struct_pcap_if>,
    device: Unique<raw::Struct_pcap_if>
}

impl Devices {
    /// Construct a new `Devices` iterator by internally using `pcap_findalldevs()`
    pub fn list_all() -> Result<Devices, Error> {
        unsafe {
            let mut errbuf = [0i8; 256];
            let mut dev_buf: *mut raw::Struct_pcap_if = ptr::null_mut();

            match raw::pcap_findalldevs(&mut dev_buf, errbuf.as_mut_ptr()) {
                0 => {
                    Ok(Devices {
                        orig: Unique::new(dev_buf),
                        device: Unique::new(dev_buf)
                    })
                },
                _ => {
                    Error::new(errbuf.as_ptr())
                }
            }
        }
    }
}

impl Iterator for Devices {
    type Item = Device;

    fn next(&mut self) -> Option<Device> {
        if self.device.is_null() {
            None
        } else {
            unsafe {
                let ret = Device {
                    name: cstr_to_string(self.device.get().name).unwrap(),
                    desc: {
                        if !self.device.get().description.is_null() {
                            Some(cstr_to_string(self.device.get().description).unwrap())
                        } else {
                            None
                        }
                    }
                };
                self.device = Unique::new(self.device.get().next);

                Some(ret)
            }
        }
    }
}

impl Drop for Devices {
    fn drop(&mut self) {
        unsafe {
            raw::pcap_freealldevs(*self.orig);
        }
    }
}

#[derive(Debug)]
/// A network device as returned from `Devices::list_all()`.
pub struct Device {
    pub name: String,
    pub desc: Option<String>
}

impl Device {
    /// Returns the default Device suitable for captures according to pcap_lookupdev,
    /// or an error from pcap.
    pub fn lookup() -> Result<Device, Error> {
        let mut errbuf = [0i8; 256];

        unsafe {
            let default_name = raw::pcap_lookupdev(errbuf.as_mut_ptr());

            if default_name.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            Ok(Device {
                name: try!(cstr_to_string(default_name)),
                desc: None
            })
        }
    }
}

impl<'a> Into<Device> for &'a str {
    fn into(self) -> Device {
        Device {
            name: self.into(),
            desc: None
        }
    }
}

/// This is a datalink link type returned from pcap.
#[derive(Debug)]
pub struct Linktype(pub i32);

impl Linktype {
    /// Gets the name of the link type, such as EN10MB
    pub fn get_name(&self) -> Result<String, Error> {
        unsafe {
            Ok(try!(cstr_to_string(raw::pcap_datalink_val_to_name(self.0))))
        }
    }

    /// Gets the description of a link type.
    pub fn get_description(&self) -> Result<String, Error> {
        unsafe {
            Ok(try!(cstr_to_string(raw::pcap_datalink_val_to_description(self.0))))
        }
    }
}

/// This is a builder for a `Capture` handle. It's useful when you want to specify certain
/// parameters, like promiscuous mode, or buffer length, before opening.
///
/// You can use `Capture::from_device()` instead of this builder, with less flexibility.
pub struct CaptureBuilder {
    buffer_size: i32,
    snaplen: i32,
    promisc: i32,
    rfmon: Option<i32>,
    timeout: i32,
}

impl CaptureBuilder {
    /// Creates a `CaptureBuilder` with sensible defaults.
    pub fn new() -> CaptureBuilder {
        CaptureBuilder {
            buffer_size: 1000000,
            snaplen: 65535,
            promisc: 0,
            rfmon: None,
            timeout: 0
        }
    }

    /// Open a `Capture` with this `CaptureBuilder` with the given device. You can
    /// provide a `Device` or an `&str` name of the device/source you would like to open.
    pub fn open<D: Into<Device>>(&self, device: D) -> Result<Capture, Error> {
        let device: Device = device.into();
        let name = CString::new(device.name).unwrap();
        // TODO: handle errors better throughout this library
        let mut errbuf = [0i8; 256];

        unsafe {
            let handle = raw::pcap_create(name.as_ptr(), errbuf.as_mut_ptr());
            if handle.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            let cap = Capture {
                handle: Unique::new(handle)
            };

            raw::pcap_set_snaplen(handle, self.snaplen);
            raw::pcap_set_buffer_size(handle, self.buffer_size);
            raw::pcap_set_promisc(handle, self.promisc);
            match self.rfmon {
                Some(rfmon) => {
                    raw::pcap_set_rfmon(handle, rfmon);
                },
                None => {}
            };
            raw::pcap_set_timeout(handle, self.timeout);

            if 0 != raw::pcap_activate(handle) {
                return Error::new(raw::pcap_geterr(handle));
            }

            Ok(cap)
        }
    }

    /// Set the read timeout for the Capture. By default, this is 0, so it will block
    /// indefinitely.
    pub fn timeout(&mut self, ms: i32) -> &mut CaptureBuilder {
        self.timeout = ms;
        self
    }

    /// Set promiscuous mode on or off. By default, this is off.
    pub fn promisc(&mut self, to: bool) -> &mut CaptureBuilder {
        self.promisc = if to {1} else {0};
        self
    }

    /// Set rfmon mode on or off. The default is maintained by pcap.
    pub fn rfmon(&mut self, to: bool) -> &mut CaptureBuilder {
        self.rfmon = Some(if to {1} else {0});
        self
    }

    /// Set the buffer size for incoming packet data.
    ///
    /// The default is 1000000. This should always be larger than the snaplen.
    pub fn buffer_size(&mut self, to: i32) -> &mut CaptureBuilder {
        self.buffer_size = to;
        self
    }

    /// Set the snaplen size (the maximum length of a packet captured into the buffer).
    /// Useful if you only want certain headers, but not the entire packet.
    ///
    /// The default is 65535
    pub fn snaplen(&mut self, to: i32) -> &mut CaptureBuilder {
        self.snaplen = to;
        self
    }
}

/// Represents a packet returned from pcap. This can be dereferenced to access
/// the underlying packet `[u8]` slice.
pub struct Packet<'a> {
    header: &'a raw::Struct_pcap_pkthdr,
    data: &'a libc::c_uchar
}

impl<'b> Deref for Packet<'b> {
    type Target = [u8];

    fn deref<'a>(&'a self) -> &'a [u8] {
        unsafe {
            slice::from_raw_parts(self.data, self.header.caplen as usize)
        }
    }
}

impl<'a> fmt::Debug for Packet<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.deref().fmt(f)
    }
}

/// This represents an open capture handle attached to a device or file.
///
/// Internally it represents a `pcap_t`.
pub struct Capture {
    handle: Unique<raw::pcap_t>
}

impl Capture {
    /// Creates a capture handle from the specified device, or an error from pcap.
    ///
    /// You can provide this a `Device` from `Devices::list_all()` or an `&str` name of
    /// the device such as "any" on Linux.
    pub fn from_device<D: Into<Device>>(device: D) -> Result<Capture, Error> {
        CaptureBuilder::new().open(device)
    }

    /// Creates a capture handle from the specified file, or an error from pcap.
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Capture, Error> {
        let name = CString::new(path.as_ref().to_str().unwrap()).unwrap();
        let mut errbuf = [0i8; 256];

        unsafe {
            let handle = raw::pcap_open_offline(name.as_ptr(), errbuf.as_mut_ptr());
            if handle.is_null() {
                return Error::new(errbuf.as_ptr());
            }

            let cap = Capture {
                handle: Unique::new(handle)
            };

            Ok(cap)
        }
    }

    /// List the datalink types that this captured device supports.
    pub fn list_datalinks(&mut self) -> Result<Vec<Linktype>, Error> {
        unsafe {
            let mut links: *mut i32 = ptr::null_mut();

            let num = raw::pcap_list_datalinks(*self.handle, &mut links);

            if num == PCAP_ERROR_NOT_ACTIVATED {
                raw::pcap_free_datalinks(links);
                panic!("It should not be possible to run list_datalinks on a Capture that is not activated, please report this bug!")
            } else if num < 0 {
                raw::pcap_free_datalinks(links);
                Error::new(raw::pcap_geterr(*self.handle))
            } else {
                let slice = slice::from_raw_parts(links, num as usize).iter().map(|&a| Linktype(a)).collect();
                raw::pcap_free_datalinks(links);

                Ok(slice)
            }
        }
    }

    /// Set the datalink type for the current capture handle.
    pub fn set_datalink(&mut self, linktype: Linktype) -> Result<(), Error> {
        unsafe {
            match raw::pcap_set_datalink(*self.handle, linktype.0) {
                0 => {
                    Ok(())
                },
                _ => {
                    Error::new(raw::pcap_geterr(*self.handle))
                }
            }
        }
    }

    /// Get the current datalink type for this capture handle.
    pub fn get_datalink(&mut self) -> Linktype {
        unsafe {
            match raw::pcap_datalink(*self.handle) {
                PCAP_ERROR_NOT_ACTIVATED => {
                    panic!("It should not be possible to run get_datalink on a Capture that is not activated, please report this bug!");
                },
                lt => {
                    Linktype(lt)
                }
            }
        }
    }

    /// Blocks until a packet is returned from the capture handle or an error occurs.
    ///
    /// pcap captures packets and places them into a buffer which this function reads
    /// from. This buffer has a finite length, so if the buffer fills completely new
    /// packets will be discarded temporarily. This means that in realtime situations,
    /// you probably want to minimize the time between calls of this next() method.
    pub fn next<'a>(&'a mut self) -> Option<Packet<'a>> {
        unsafe {
            let mut header: *mut raw::Struct_pcap_pkthdr = ptr::null_mut();
            let mut packet: *const libc::c_uchar = ptr::null();
            match raw::pcap_next_ex(*self.handle, &mut header, &mut packet) {
                1 => {
                    // packet was read without issue
                    Some(Packet {
                        header: &*header,
                        data: &*packet
                    })
                },
                _ => {
                    None
                }
            }
        }
    }

    /// Adds a filter to the capture using the given BPF program string. Internally
    /// this is compiled using `pcap_compile()`.
    ///
    /// See http://biot.com/capstats/bpf.html for more information about this syntax.
    pub fn filter(&mut self, program: &str) -> Result<(), Error> {
        let program = CString::new(program).unwrap();

        unsafe {
            let mut bpf_program: raw::Struct_bpf_program = Default::default();

            if -1 == raw::pcap_compile(*self.handle, &mut bpf_program, program.as_ptr(), 0, 0) {
                return Error::new(raw::pcap_geterr(*self.handle));
            }

            if -1 == raw::pcap_setfilter(*self.handle, &mut bpf_program) {
                raw::pcap_freecode(&mut bpf_program);
                return Error::new(raw::pcap_geterr(*self.handle));
            }

            raw::pcap_freecode(&mut bpf_program);
            Ok(())
        }
    }
}

impl Drop for Capture {
    fn drop(&mut self) {
        unsafe {
            raw::pcap_close(*self.handle)
        }
    }
}

fn cstr_to_string(ptr: *const libc::c_char) -> Result<String, str::Utf8Error> {
    Ok(try!(str::from_utf8(unsafe{CStr::from_ptr(ptr)}.to_bytes())).to_string())
}
<|endoftext|>


<commit_before>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let _server = Server::start(&"127.0.0.1:3030".parse().unwrap(), Arc::new(io), vec![AccessControlAllowOrigin::Null]);
//! }
//! ```

extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;

mod cors;

use std::ops::Deref;
use std::sync::{Arc, Mutex};
use std::io::{Read, Write};
use std::net::SocketAddr;
use hyper::header::{Headers, Allow, ContentType, AccessControlAllowHeaders};
use hyper::method::Method;
use hyper::mime;
use hyper::server::{Request, Response};
use hyper::{Next, Encoder, Decoder};
use hyper::net::HttpStream;
use unicase::UniCase;
use self::jsonrpc::{IoHandler};

pub use hyper::header::AccessControlAllowOrigin;

pub type ServerResult = Result<Server, RpcServerError>;

/// RPC Server startup error
#[derive(Debug)]
pub enum RpcServerError {
	IoError(std::io::Error),
	Other(hyper::error::Error),
}

impl From<hyper::error::Error> for RpcServerError {
	fn from(err: hyper::error::Error) -> Self {
		match err {
			hyper::error::Error::Io(e) => RpcServerError::IoError(e),
			e => RpcServerError::Other(e)
		}
	}
}

/// PanicHandling function
pub struct PanicHandler {
	pub handler: Arc<Mutex<Option<Box<Fn() -> () + Send + 'static>>>>
}

/// jsonrpc http request handler.
pub struct ServerHandler {
	panic_handler: PanicHandler,
	jsonrpc_handler: Arc<IoHandler>,
	cors_domains: Vec<AccessControlAllowOrigin>,
	request: String,
	origin: Option<String>,
	response: Option<String>,
	error_code:  hyper::status::StatusCode,
	write_pos: usize,
}

impl Drop for ServerHandler {
	fn drop(&mut self) {
		if ::std::thread::panicking() {
			let handler = self.panic_handler.handler.lock().unwrap();
			if let Some(ref h) = *handler.deref() {
				h();
			}
		}
	}
}

impl ServerHandler {
	/// Create new request handler.
	pub fn new(jsonrpc_handler: Arc<IoHandler>, cors_domains: Vec<AccessControlAllowOrigin>, panic_handler: PanicHandler) -> Self {
		ServerHandler {
			panic_handler: panic_handler,
			jsonrpc_handler: jsonrpc_handler,
			cors_domains: cors_domains,
			request: String::new(),
			origin: None,
			response: None,
			error_code: hyper::status::StatusCode::MethodNotAllowed,
			write_pos: 0,
		}
	}

	fn response_headers(&self, origin: &Option<String>) -> Headers {
		let mut headers = Headers::new();
		headers.set(
			Allow(vec![
				Method::Options, Method::Post
			])
		);
		headers.set(ContentType::json());
		headers.set(
			AccessControlAllowHeaders(vec![
				UniCase("origin".to_owned()),
				UniCase("content-type".to_owned()),
				UniCase("accept".to_owned()),
			])
		);

		if let Some(cors_domain) = cors::get_cors_header(&self.cors_domains, origin) {
			headers.set(cors_domain);
		}

		headers
	}
}

impl hyper::server::Handler<HttpStream> for ServerHandler {
	fn on_request(&mut self, request: Request) -> Next {
		// Read origin
		self.origin = cors::read_origin(&request);
		// Validate the ContentType header
		// to prevent Cross-Origin XHRs with text/plain
		let content_type = request.headers().get::<ContentType>();
		if let Some(&ContentType(mime::Mime(mime::TopLevel::Application, mime::SubLevel::Json, _))) = content_type {
			match *request.method() {
				Method::Options => {
					self.response = Some(String::new());
					Next::write()
				},
				Method::Post => Next::read(),
				_ => Next::write(),
			}
		} else {
			self.error_code = hyper::status::StatusCode::UnsupportedMediaType;
			// Just return error
			Next::write()
		}
	}

	/// This event occurs each time the `Request` is ready to be read from.
	fn on_request_readable(&mut self, decoder: &mut Decoder<HttpStream>) -> Next {
		match decoder.read_to_string(&mut self.request) {
			Ok(0) => {
				self.response = self.jsonrpc_handler.handle_request(&self.request);
				match self.response {
					Some(ref mut r) => r.push('\n'),
					_ => {
						self.error_code = hyper::status::StatusCode::BadRequest;
					}
				}
				Next::write()
			}
			Ok(_) => {
				Next::read()
			}
			Err(e) => match e.kind() {
				::std::io::ErrorKind::WouldBlock => Next::read(),
				_ => {
					//trace!("Read error: {}", e);
					Next::end()
				}
			}
		}
	}

		/// This event occurs after the first time this handled signals `Next::write()`.
	fn on_response(&mut self, response: &mut Response) -> Next {
		*response.headers_mut() = self.response_headers(&self.origin);
		if self.response.is_none() {
			response.set_status(self.error_code);
		}
		Next::write()
	}

		/// This event occurs each time the `Response` is ready to be written to.
		fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
		if let Some(ref response) = self.response {
			let bytes = response.as_bytes();
			if bytes.len() == self.write_pos {
				Next::end()
			} else {
				match encoder.write(&bytes[self.write_pos ..]) {
					Ok(0) => {
						Next::write()
					}
					Ok(bytes) => {
						self.write_pos += bytes;
						Next::write()
					}
					Err(e) => match e.kind() {
						::std::io::ErrorKind::WouldBlock => Next::write(),
						_ => {
							//trace!("Write error: {}", e);
							Next::end()
						}
					}
				}
			}
		} else {
			Next::end()
		}
	}
}

/// jsonrpc http server.
///
/// ```no_run
/// extern crate jsonrpc_core;
/// extern crate jsonrpc_http_server;
///
/// use std::sync::Arc;
/// use jsonrpc_core::*;
/// use jsonrpc_http_server::*;
///
/// struct SayHello;
/// impl MethodCommand for SayHello {
/// 	fn execute(&self, _params: Params) -> Result<Value, Error> {
/// 		Ok(Value::String("hello".to_string()))
/// 	}
/// }
///
/// fn main() {
/// 	let io = IoHandler::new();
/// 	io.add_method("say_hello", SayHello);
/// 	let _server = Server::start(&"127.0.0.1:3030".parse().unwrap(), Arc::new(io), vec![AccessControlAllowOrigin::Null]);
/// }
/// ```
pub struct Server {
	server: Option<hyper::server::Listening>,
	panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>
}

impl Server {
	pub fn start(addr: &SocketAddr, jsonrpc_handler: Arc<IoHandler>, cors_domains: Vec<AccessControlAllowOrigin>) -> ServerResult {
		let panic_handler = Arc::new(Mutex::new(None));
		let panic_for_server = panic_handler.clone();
		let srv = try!(try!(hyper::Server::http(addr)).handle(move |_| {
			let handler = PanicHandler { handler: panic_for_server.clone() };
			ServerHandler::new(jsonrpc_handler.clone(), cors_domains.clone(), handler)
		}));
		Ok(Server {
			server: Some(srv),
			panic_handler: panic_handler,
		})
	}

	pub fn set_panic_handler<F>(&self, handler: F)
		where F : Fn() -> () + Send + 'static {
		*self.panic_handler.lock().unwrap() = Some(Box::new(handler));
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.server.take().unwrap().close()
	}
}
<commit_msg>Fixing content-type validation in case of OPTIONS pre-flight request<commit_after>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let _server = Server::start(&"127.0.0.1:3030".parse().unwrap(), Arc::new(io), vec![AccessControlAllowOrigin::Null]);
//! }
//! ```

extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;

mod cors;

use std::ops::Deref;
use std::sync::{Arc, Mutex};
use std::io::{Read, Write};
use std::net::SocketAddr;
use hyper::header::{Headers, Allow, ContentType, AccessControlAllowHeaders};
use hyper::method::Method;
use hyper::mime;
use hyper::server::{Request, Response};
use hyper::{Next, Encoder, Decoder};
use hyper::net::HttpStream;
use unicase::UniCase;
use self::jsonrpc::{IoHandler};

pub use hyper::header::AccessControlAllowOrigin;

pub type ServerResult = Result<Server, RpcServerError>;

/// RPC Server startup error
#[derive(Debug)]
pub enum RpcServerError {
	IoError(std::io::Error),
	Other(hyper::error::Error),
}

impl From<hyper::error::Error> for RpcServerError {
	fn from(err: hyper::error::Error) -> Self {
		match err {
			hyper::error::Error::Io(e) => RpcServerError::IoError(e),
			e => RpcServerError::Other(e)
		}
	}
}

/// PanicHandling function
pub struct PanicHandler {
	pub handler: Arc<Mutex<Option<Box<Fn() -> () + Send + 'static>>>>
}

/// jsonrpc http request handler.
pub struct ServerHandler {
	panic_handler: PanicHandler,
	jsonrpc_handler: Arc<IoHandler>,
	cors_domains: Vec<AccessControlAllowOrigin>,
	request: String,
	origin: Option<String>,
	response: Option<String>,
	error_code:  hyper::status::StatusCode,
	write_pos: usize,
}

impl Drop for ServerHandler {
	fn drop(&mut self) {
		if ::std::thread::panicking() {
			let handler = self.panic_handler.handler.lock().unwrap();
			if let Some(ref h) = *handler.deref() {
				h();
			}
		}
	}
}

impl ServerHandler {
	/// Create new request handler.
	pub fn new(jsonrpc_handler: Arc<IoHandler>, cors_domains: Vec<AccessControlAllowOrigin>, panic_handler: PanicHandler) -> Self {
		ServerHandler {
			panic_handler: panic_handler,
			jsonrpc_handler: jsonrpc_handler,
			cors_domains: cors_domains,
			request: String::new(),
			origin: None,
			response: None,
			error_code: hyper::status::StatusCode::MethodNotAllowed,
			write_pos: 0,
		}
	}

	fn response_headers(&self, origin: &Option<String>) -> Headers {
		let mut headers = Headers::new();
		headers.set(
			Allow(vec![
				Method::Options, Method::Post
			])
		);
		headers.set(ContentType::json());
		headers.set(
			AccessControlAllowHeaders(vec![
				UniCase("origin".to_owned()),
				UniCase("content-type".to_owned()),
				UniCase("accept".to_owned()),
			])
		);

		if let Some(cors_domain) = cors::get_cors_header(&self.cors_domains, origin) {
			headers.set(cors_domain);
		}

		headers
	}
}

impl hyper::server::Handler<HttpStream> for ServerHandler {
	fn on_request(&mut self, request: Request) -> Next {
		// Read origin
		self.origin = cors::read_origin(&request);

		match *request.method() {
			// Don't validate content type on options
			Method::Options => {
				self.response = Some(String::new());
				Next::write()
			},
			Method::Post => {
				// Validate the ContentType header
				// to prevent Cross-Origin XHRs with text/plain
				let content_type = request.headers().get::<ContentType>();
				if let Some(&ContentType(mime::Mime(mime::TopLevel::Application, mime::SubLevel::Json, _))) = content_type {
					Next::read()
				} else {
					self.error_code = hyper::status::StatusCode::UnsupportedMediaType;
					// Just return error
					Next::write()
				}
			},
			_ => Next::write(),
		}
	}

	/// This event occurs each time the `Request` is ready to be read from.
	fn on_request_readable(&mut self, decoder: &mut Decoder<HttpStream>) -> Next {
		match decoder.read_to_string(&mut self.request) {
			Ok(0) => {
				self.response = self.jsonrpc_handler.handle_request(&self.request);
				match self.response {
					Some(ref mut r) => r.push('\n'),
					_ => {
						self.error_code = hyper::status::StatusCode::BadRequest;
					}
				}
				Next::write()
			}
			Ok(_) => {
				Next::read()
			}
			Err(e) => match e.kind() {
				::std::io::ErrorKind::WouldBlock => Next::read(),
				_ => {
					//trace!("Read error: {}", e);
					Next::end()
				}
			}
		}
	}

		/// This event occurs after the first time this handled signals `Next::write()`.
	fn on_response(&mut self, response: &mut Response) -> Next {
		*response.headers_mut() = self.response_headers(&self.origin);
		if self.response.is_none() {
			response.set_status(self.error_code);
		}
		Next::write()
	}

		/// This event occurs each time the `Response` is ready to be written to.
		fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
		if let Some(ref response) = self.response {
			let bytes = response.as_bytes();
			if bytes.len() == self.write_pos {
				Next::end()
			} else {
				match encoder.write(&bytes[self.write_pos ..]) {
					Ok(0) => {
						Next::write()
					}
					Ok(bytes) => {
						self.write_pos += bytes;
						Next::write()
					}
					Err(e) => match e.kind() {
						::std::io::ErrorKind::WouldBlock => Next::write(),
						_ => {
							//trace!("Write error: {}", e);
							Next::end()
						}
					}
				}
			}
		} else {
			Next::end()
		}
	}
}

/// jsonrpc http server.
///
/// ```no_run
/// extern crate jsonrpc_core;
/// extern crate jsonrpc_http_server;
///
/// use std::sync::Arc;
/// use jsonrpc_core::*;
/// use jsonrpc_http_server::*;
///
/// struct SayHello;
/// impl MethodCommand for SayHello {
/// 	fn execute(&self, _params: Params) -> Result<Value, Error> {
/// 		Ok(Value::String("hello".to_string()))
/// 	}
/// }
///
/// fn main() {
/// 	let io = IoHandler::new();
/// 	io.add_method("say_hello", SayHello);
/// 	let _server = Server::start(&"127.0.0.1:3030".parse().unwrap(), Arc::new(io), vec![AccessControlAllowOrigin::Null]);
/// }
/// ```
pub struct Server {
	server: Option<hyper::server::Listening>,
	panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>
}

impl Server {
	pub fn start(addr: &SocketAddr, jsonrpc_handler: Arc<IoHandler>, cors_domains: Vec<AccessControlAllowOrigin>) -> ServerResult {
		let panic_handler = Arc::new(Mutex::new(None));
		let panic_for_server = panic_handler.clone();
		let srv = try!(try!(hyper::Server::http(addr)).handle(move |_| {
			let handler = PanicHandler { handler: panic_for_server.clone() };
			ServerHandler::new(jsonrpc_handler.clone(), cors_domains.clone(), handler)
		}));
		Ok(Server {
			server: Some(srv),
			panic_handler: panic_handler,
		})
	}

	pub fn set_panic_handler<F>(&self, handler: F)
		where F : Fn() -> () + Send + 'static {
		*self.panic_handler.lock().unwrap() = Some(Box::new(handler));
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.server.take().unwrap().close()
	}
}
<|endoftext|>


<commit_before>//! Body Parser middleware for Iron
#![crate_id = "bodyparser"]
#![license = "MIT"]

extern crate iron;
extern crate serialize;

use iron::{Request, Response, Middleware, Alloy};
use iron::middleware::{Status, Continue, Unwind};

use serialize::json;
use serialize::json::Json;

#[deriving(Clone)]
struct Parsed(Json);

#[deriving(Clone)]
pub struct BodyParser;

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

impl Middleware for BodyParser {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        if !req.body.is_empty() {
            let parse = json::from_str(req.body.as_slice());
            match parse {
                Ok(k) => {
                    alloy.insert::<Parsed>(Parsed(k));
                },
                Err(k) => {
                    return Continue;
                }
            }
        }
        Continue
    }
}
<commit_msg>(refactor) Error variable set to _<commit_after>//! Body Parser middleware for Iron
#![crate_id = "bodyparser"]
#![license = "MIT"]

extern crate iron;
extern crate serialize;

use iron::{Request, Response, Middleware, Alloy};
use iron::middleware::{Status, Continue, Unwind};

use serialize::json;
use serialize::json::Json;

#[deriving(Clone)]
struct Parsed(Json);

#[deriving(Clone)]
pub struct BodyParser;

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

impl Middleware for BodyParser {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        if !req.body.is_empty() {
            let parse = json::from_str(req.body.as_slice());
            match parse {
                Ok(parsed) => {
                    alloy.insert::<Parsed>(Parsed(parsed));
                },
                Err(_) => {
                    return Continue;
                }
            }
        }
        Continue
    }
}
<|endoftext|>


<commit_before>#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {Forward, Reverse}
use self::Direction::*;

impl Direction {
	fn reverse(self) -> Direction {
		match self {
			Forward => Reverse,
			Reverse => Forward
		}
	}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GlyphOrient {Perpendicular, Parallel}
use self::GlyphOrient::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct DirBehavior(pub Direction, pub GlyphOrient);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum DirPreference {Horiz(DirBehavior), Vert(DirBehavior), BiOrient(DirBehavior, DirBehavior)}	// enable scripts without preference?
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Rot180 {Normal, Rotated}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ItemTypesetting(pub DirBehavior, pub Rot180);

impl ItemTypesetting {
	fn effective_direction(&self) -> Direction {
		match self.1 {
			Rot180::Normal => self.0 . 0,
			Rot180::Rotated => self.0 . 0 .reverse()
		}
	}
}

/// ISO 15924 alphabetical code
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ScriptCode([u8; 4]);

pub static LATIN: ScriptCode = ScriptCode(['L' as u8, 'a' as u8, 't' as u8, 'n' as u8]);	// "Latn"

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MainAxis {Ltr, Rtl, Ttb, Btt}

pub struct NonNativeConf;

pub struct Run<'a>(pub &'a str, pub ScriptCode);

pub fn make_default_streak<'a>(run: &'a Run, main_axis: MainAxis) -> Item<'a> {
	use self::MainAxis::*;
	Item {
		text: run.0,
		script: run.1,
		dir: ItemTypesetting(DirBehavior(Forward, Perpendicular), if run.1 == LATIN {
			match main_axis {
				Ltr | Ttb => Rot180::Normal,
				Rtl | Btt => Rot180::Rotated
			}
		} else {
			unimplemented!();
		})
	}
}

pub fn make_runs(s: &str) -> Vec<Run> {vec![Run(s, LATIN)]}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Item<'text>{
	pub text: &'text str,
	pub script: ScriptCode,
	pub dir: ItemTypesetting
}

impl<'a> Item<'a> {
	/// what order do the parts have if you split the streak
	pub fn direction(&self) -> Direction {self.dir.effective_direction()}
}

pub fn bidi_algorithm(streaks: &mut [Item]) {}

pub struct FontPreference<'a>(Font<'a>);

/// contains glyphs and typesetting information
pub struct FontCollection<'a>(&'a[u8]);
/// what features of the font collection do we want to use?
pub struct FontConfiguration;

/// contains character mapping
pub struct Font<'a>{
	pub cmap: CMap<'a>,
	glyph_src: &'a FontCollection<'a>
}

struct GlyphPoint(i16, i16);
enum ContourSegment {
	Line(GlyphPoint, GlyphPoint),
	Curve(GlyphPoint, GlyphPoint, GlyphPoint)
}

pub fn read_u32(data: &[u8]) -> Option<u32> {
	if data.len() > 3 {
		Some((data[0] as u32) << 24 | (data[1] as u32) << 16 | (data[2] as u32) << 8 | data[3] as u32)
	} else {
		None
	}
}

pub fn read_u16(data: &[u8]) -> Option<u16> {
	if data.len() > 1 {
		Some((data[0] as u16) << 8 | data[1] as u16)
	} else {
		None
	}
}

fn fourcc(tag: u32) -> String {
	let mut s = String::with_capacity(4);
	s.push((tag >> 24) as u8 as char);
	s.push((tag >> 16) as u8 as char);
	s.push((tag >> 8) as u8 as char);
	s.push(tag as u8 as char);
	s
}

macro_rules! try_opt {
	($e:expr) => (match $e {Some(x)=>x, None=>return None})
}

fn scan_table_records(data: &[u8], start: usize, label: u32, num_tables: usize) -> Option<(usize, &[u8])> {
	for pos in start..num_tables {
		if try_opt!(read_u32(&data[12+16*pos..])) == label {
			let start = read_u32(&data[12+16*pos+8..]).unwrap() as usize;
			return Some((pos, &data[start..read_u32(&data[12+16*pos+12..]).unwrap() as usize+start]));
		}
	}
	None
}

fn find_best_cmap(cmap: &[u8]) -> Option<&[u8]> {
	let mut bmp = None;
	for encoding in 0..read_u16(&cmap[2..]).unwrap() as usize {
		let enc_header = &(&cmap[4+8*encoding..])[..8];
		let (plat, enc) = (read_u16(enc_header).unwrap(), read_u16(&enc_header[2..]).unwrap());
		match (plat, enc) {
			(0, 3) | (3, 1) => {bmp=Some(&cmap[try_opt!(read_u32(&enc_header[4..])) as usize..]);},
			(0, 4) | (3, 10) => return Some(&cmap[try_opt!(read_u32(&enc_header[4..])) as usize..]),
			_ => {}	// unknown encoding
		}
	}
	bmp
}

pub struct CMap<'otf>(Encoding<'otf>);

impl<'otf> CMap<'otf> {pub fn lookup(&self, c: char) -> Option<GlyphIndex> {self.0.lookup(c)}}

enum Encoding<'a> {
	Fmt4(CmapFmt4<'a>)
}

impl<'a> Encoding<'a> {
	pub fn lookup(&self, c: char) -> Option<GlyphIndex> {
		match *self {
			Encoding::Fmt4 (CmapFmt4 {end, start, delta, crazy_indexing_part: range_offset}) => {
				if c as u32 > 0xffff {return Some(GlyphIndex(0))}
				let mut range = 0..end.len()/2;
				while range.start != range.end {
					let pivot = ((range.end - range.start) & !1) + range.start*2;
					let pivot_val = read_u16(&end[pivot..]).unwrap();
					range = if pivot_val < c as u16 {
						pivot/2+1..range.end
					} else {
						range.start..pivot/2
					};
				}
				let seg_offset = range.start*2;
				let block_start = read_u16(&start[seg_offset..]).unwrap();
				if block_start > c as u16 {return Some(GlyphIndex(0))}
				let block_index = c as u16 - block_start;
				return Some(GlyphIndex((read_u16(&delta[seg_offset..]).unwrap()).wrapping_add({
					let offset = read_u16(&range_offset[seg_offset..]).unwrap();
					if offset == 0 {
						block_index
					} else {	// this path is untested because the spec is really weird and I've never seen it used
						let res = read_u16(&range_offset[seg_offset+(offset as usize &!1)+block_index as usize..]).unwrap();
						if res == 0 {
							return Some(GlyphIndex(0))
						} else {
							res
						}
					}
				})))
			}
		}
	}
}

struct CmapFmt4<'a> {
	end: &'a[u8],
	start: &'a[u8],
	delta: &'a[u8],
	crazy_indexing_part: &'a[u8]
}

fn load_enc_table(mut enc: &[u8]) -> Option<Encoding> {
	let format = try_opt!(read_u16(enc));
	match format {
		4 => {
			let len = try_opt!(read_u16(&enc[2..])) as usize;
			if len > enc.len() {return None}
			enc = &enc[..len];
			let segsX2 = try_opt!(read_u16(&enc[6..])) as usize;
			if segsX2 < 2 || segsX2 % 2 != 0 || 4*segsX2 + 16 < len {return None}
			let end = &enc[14..14+segsX2];
			if read_u16(&end[segsX2-2..]).unwrap() != 0xffff {return None}
			Some(Encoding::Fmt4(CmapFmt4{
				end: end,
				start: &enc[16+segsX2..16+2*segsX2],
				delta: &enc[16+2*segsX2..16+3*segsX2],
				crazy_indexing_part: &enc[16+3*segsX2..]
			}))
		},
		_ => None	// not implemented
	}
}

pub fn load_font_collection(data: &[u8]) -> Option<FontCollection> {
	Some(FontCollection(data))
}

pub fn load_font<'a>(collection: &'a FontCollection<'a>, font: &str) -> Option<Font<'a>> {
	let data = collection.0;
	let num_tables = try_opt!(read_u16(&data[4..])) as usize;
	let (_pos, cmap) = try_opt!(scan_table_records(data, 0, 0x636d6170, num_tables));
	let best_enc = try_opt!(find_best_cmap(cmap));
	let enc = try_opt!(load_enc_table(best_enc));
	Some(Font {cmap: CMap(enc), glyph_src: collection})
}

#[derive(Debug)]
pub struct GlyphIndex(u16);

#[derive(Debug)]
pub struct GlyphMap<'text> {
	pub range: &'text str,
	pub dir: Direction,
	pub glyph_off: usize,
	pub span: u16	// between which caret positions of a ligature?
}

pub struct Burst<'text, 'a, 'b: 'a> {
	pub glyphs: Vec<GlyphIndex>,
	pub font: &'a Font<'b>,
	pub dir: ItemTypesetting,
	pub glyph_map: Vec<GlyphMap<'text>>
}

pub fn shape<'text, 'a, 'b: 'a>(item: Item<'text>, font: &'a Font<'b>) -> Option<Burst<'text, 'a, 'b>> {
	let (mut glyphs, mut glyph_map) = (Vec::with_capacity(item.text.len()), Vec::with_capacity(item.text.len()));	// 1 char ⇒ 1 glyph (at this stage) is at least one byte long
	let mut rest = item.text;
	while rest.len() > 0 {
		let c = rest.chars().next().unwrap();
		let idx = try_opt!(font.cmap.lookup(c));
		glyphs.push(idx);
		let size = c.len_utf8();
		glyph_map.push(GlyphMap {
			range: &rest[..size],
			dir: Forward,
			glyph_off: glyphs.len() - 1,
			span: 0
		});
		rest = &rest[size..];
	}
	Some(Burst {glyphs: glyphs, glyph_map: glyph_map, font: font, dir: item.dir})
}<commit_msg>Burst merging<commit_after>#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {Forward, Reverse}
use self::Direction::*;

impl Direction {
	fn reverse(self) -> Direction {
		match self {
			Forward => Reverse,
			Reverse => Forward
		}
	}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GlyphOrient {Perpendicular, Parallel}
use self::GlyphOrient::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct DirBehavior(pub Direction, pub GlyphOrient);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum DirPreference {Horiz(DirBehavior), Vert(DirBehavior), BiOrient(DirBehavior, DirBehavior)}	// enable scripts without preference?
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Rot180 {Normal, Rotated}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ItemTypesetting(pub DirBehavior, pub Rot180);

impl ItemTypesetting {
	fn effective_direction(&self) -> Direction {
		match self.1 {
			Rot180::Normal => self.0 . 0,
			Rot180::Rotated => self.0 . 0 .reverse()
		}
	}
}

/// ISO 15924 alphabetical code
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ScriptCode([u8; 4]);

pub static LATIN: ScriptCode = ScriptCode(['L' as u8, 'a' as u8, 't' as u8, 'n' as u8]);	// "Latn"

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MainAxis {Ltr, Rtl, Ttb, Btt}

pub struct NonNativeConf;

pub struct Run<'a>(pub &'a str, pub ScriptCode);

pub fn make_default_streak<'a>(run: &'a Run, main_axis: MainAxis) -> Item<'a> {
	use self::MainAxis::*;
	Item {
		text: run.0,
		script: run.1,
		dir: ItemTypesetting(DirBehavior(Forward, Perpendicular), if run.1 == LATIN {
			match main_axis {
				Ltr | Ttb => Rot180::Normal,
				Rtl | Btt => Rot180::Rotated
			}
		} else {
			unimplemented!();
		})
	}
}

pub fn make_runs(s: &str) -> Vec<Run> {vec![Run(s, LATIN)]}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Item<'text>{
	pub text: &'text str,
	pub script: ScriptCode,
	pub dir: ItemTypesetting
}

impl<'a> Item<'a> {
	/// what order do the parts have if you split the streak
	pub fn direction(&self) -> Direction {self.dir.effective_direction()}
}

pub fn bidi_algorithm(streaks: &mut [Item]) {}

pub struct FontPreference<'a>(Font<'a>);

/// contains glyphs and typesetting information
#[derive(PartialEq, Clone, Copy)]
pub struct FontCollection<'a>(&'a[u8]);
/// what features of the font collection do we want to use?
pub struct FontConfiguration;

/// contains character mapping
#[derive(PartialEq, Clone, Copy)]
pub struct Font<'a>{
	pub cmap: CMap<'a>,
	glyph_src: &'a FontCollection<'a>
}

struct GlyphPoint(i16, i16);
enum ContourSegment {
	Line(GlyphPoint, GlyphPoint),
	Curve(GlyphPoint, GlyphPoint, GlyphPoint)
}

pub fn read_u32(data: &[u8]) -> Option<u32> {
	if data.len() > 3 {
		Some((data[0] as u32) << 24 | (data[1] as u32) << 16 | (data[2] as u32) << 8 | data[3] as u32)
	} else {
		None
	}
}

pub fn read_u16(data: &[u8]) -> Option<u16> {
	if data.len() > 1 {
		Some((data[0] as u16) << 8 | data[1] as u16)
	} else {
		None
	}
}

fn fourcc(tag: u32) -> String {
	let mut s = String::with_capacity(4);
	s.push((tag >> 24) as u8 as char);
	s.push((tag >> 16) as u8 as char);
	s.push((tag >> 8) as u8 as char);
	s.push(tag as u8 as char);
	s
}

macro_rules! try_opt {
	($e:expr) => (match $e {Some(x)=>x, None=>return None})
}

fn scan_table_records(data: &[u8], start: usize, label: u32, num_tables: usize) -> Option<(usize, &[u8])> {
	for pos in start..num_tables {
		if try_opt!(read_u32(&data[12+16*pos..])) == label {
			let start = read_u32(&data[12+16*pos+8..]).unwrap() as usize;
			return Some((pos, &data[start..read_u32(&data[12+16*pos+12..]).unwrap() as usize+start]));
		}
	}
	None
}

fn find_best_cmap(cmap: &[u8]) -> Option<&[u8]> {
	let mut bmp = None;
	for encoding in 0..read_u16(&cmap[2..]).unwrap() as usize {
		let enc_header = &(&cmap[4+8*encoding..])[..8];
		let (plat, enc) = (read_u16(enc_header).unwrap(), read_u16(&enc_header[2..]).unwrap());
		match (plat, enc) {
			(0, 3) | (3, 1) => {bmp=Some(&cmap[try_opt!(read_u32(&enc_header[4..])) as usize..]);},
			(0, 4) | (3, 10) => return Some(&cmap[try_opt!(read_u32(&enc_header[4..])) as usize..]),
			_ => {}	// unknown encoding
		}
	}
	bmp
}

#[derive(PartialEq, Clone, Copy)]
pub struct CMap<'otf>(Encoding<'otf>);

impl<'otf> CMap<'otf> {pub fn lookup(&self, c: char) -> Option<GlyphIndex> {self.0.lookup(c)}}

#[derive(PartialEq, Clone, Copy)]
enum Encoding<'a> {
	Fmt4(CmapFmt4<'a>)
}

impl<'a> Encoding<'a> {
	pub fn lookup(&self, c: char) -> Option<GlyphIndex> {
		match *self {
			Encoding::Fmt4 (CmapFmt4 {end, start, delta, crazy_indexing_part: range_offset}) => {
				if c as u32 > 0xffff {return Some(GlyphIndex(0))}
				let mut range = 0..end.len()/2;
				while range.start != range.end {
					let pivot = ((range.end - range.start) & !1) + range.start*2;
					let pivot_val = read_u16(&end[pivot..]).unwrap();
					range = if pivot_val < c as u16 {
						pivot/2+1..range.end
					} else {
						range.start..pivot/2
					};
				}
				let seg_offset = range.start*2;
				let block_start = read_u16(&start[seg_offset..]).unwrap();
				if block_start > c as u16 {return Some(GlyphIndex(0))}
				let block_index = c as u16 - block_start;
				return Some(GlyphIndex((read_u16(&delta[seg_offset..]).unwrap()).wrapping_add({
					let offset = read_u16(&range_offset[seg_offset..]).unwrap();
					if offset == 0 {
						block_index
					} else {	// this path is untested because the spec is really weird and I've never seen it used
						let res = read_u16(&range_offset[seg_offset+(offset as usize &!1)+block_index as usize..]).unwrap();
						if res == 0 {
							return Some(GlyphIndex(0))
						} else {
							res
						}
					}
				})))
			}
		}
	}
}

#[derive(PartialEq, Clone, Copy)]
struct CmapFmt4<'a> {
	end: &'a[u8],
	start: &'a[u8],
	delta: &'a[u8],
	crazy_indexing_part: &'a[u8]
}

fn load_enc_table(mut enc: &[u8]) -> Option<Encoding> {
	let format = try_opt!(read_u16(enc));
	match format {
		4 => {
			let len = try_opt!(read_u16(&enc[2..])) as usize;
			if len > enc.len() {return None}
			enc = &enc[..len];
			let segsX2 = try_opt!(read_u16(&enc[6..])) as usize;
			if segsX2 < 2 || segsX2 % 2 != 0 || 4*segsX2 + 16 < len {return None}
			let end = &enc[14..14+segsX2];
			if read_u16(&end[segsX2-2..]).unwrap() != 0xffff {return None}
			Some(Encoding::Fmt4(CmapFmt4{
				end: end,
				start: &enc[16+segsX2..16+2*segsX2],
				delta: &enc[16+2*segsX2..16+3*segsX2],
				crazy_indexing_part: &enc[16+3*segsX2..]
			}))
		},
		_ => None	// not implemented
	}
}

pub fn load_font_collection(data: &[u8]) -> Option<FontCollection> {
	Some(FontCollection(data))
}

static CMAP_TAG: u32 = 0x636d6170;

pub fn load_font<'a>(collection: &'a FontCollection<'a>, font: &str) -> Option<Font<'a>> {
	let data = collection.0;
	let num_tables = try_opt!(read_u16(&data[4..])) as usize;
	let (_pos, cmap) = try_opt!(scan_table_records(data, 0, CMAP_TAG, num_tables));
	let best_enc = try_opt!(find_best_cmap(cmap));
	let enc = try_opt!(load_enc_table(best_enc));
	Some(Font {cmap: CMap(enc), glyph_src: collection})
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct GlyphIndex(u16);

#[derive(Debug, Clone, Copy)]
pub struct GlyphMap<'text> {
	pub range: &'text str,
	pub dir: Direction,
	pub glyph_off: usize,
	pub span: u16	// between which caret positions of a ligature?
}

pub struct Burst<'text, 'a> {
	pub glyphs: Vec<GlyphIndex>,
	pub font: &'a FontCollection<'a>,
	pub dir: ItemTypesetting,
	pub glyph_map: Vec<GlyphMap<'text>>
}

pub fn shape<'text, 'a, 'b: 'a>(item: Item<'text>, font: &'a Font<'b>) -> Option<Burst<'text, 'b>> {
	let (mut glyphs, mut glyph_map) = (Vec::with_capacity(item.text.len()), Vec::with_capacity(item.text.len()));	// 1 char ⇒ 1 glyph (at this stage) is at least one byte long
	let mut rest = item.text;
	while rest.len() > 0 {
		let c = rest.chars().next().unwrap();
		let idx = try_opt!(font.cmap.lookup(c));
		glyphs.push(idx);
		let size = c.len_utf8();
		glyph_map.push(GlyphMap {
			range: &rest[..size],
			dir: Forward,
			glyph_off: glyphs.len() - 1,
			span: 0
		});
		rest = &rest[size..];
	}
	Some(Burst {glyphs: glyphs, glyph_map: glyph_map, font: font.glyph_src, dir: item.dir})
}

pub fn merge_bursts<'text, 'a, I: IntoIterator<Item=Burst<'text, 'a>>>(bursts: I) -> Vec<Burst<'text, 'a>> {
	let iter = bursts.into_iter();
	let mut res: Vec<Burst> = Vec::with_capacity(iter.size_hint().0);
	for mut burst in iter {
		if let Some(last) = res.last_mut() {
			if burst.dir == last.dir && *burst.font == *last.font {
				if burst.dir.effective_direction() == Forward {
					last.glyphs.extend_from_slice(&burst.glyphs);
					last.glyph_map.extend_from_slice(&burst.glyph_map);
				} else {
					burst.glyphs.extend_from_slice(&last.glyphs);
					last.glyphs = burst.glyphs;
					burst.glyph_map.extend_from_slice(&last.glyph_map);
					last.glyph_map = burst.glyph_map;
				}
				continue
			}
		}
		res.push(burst);
	}
	res
}

#[test]
fn test_burst_merge() {
	let fc = FontCollection(&[]);
	let res = merge_bursts(vec![
		Burst {glyphs: Vec::new(), font: &fc, dir: ItemTypesetting(DirBehavior(Forward, Perpendicular), Rot180::Rotated), glyph_map: Vec::new()},
		Burst {glyphs: vec![GlyphIndex(2)], font: &fc, dir: ItemTypesetting(DirBehavior(Reverse, Perpendicular), Rot180::Normal), glyph_map: Vec::new()},
		Burst {glyphs: vec![GlyphIndex(1)], font: &fc, dir: ItemTypesetting(DirBehavior(Reverse, Perpendicular), Rot180::Normal), glyph_map: Vec::new()},
		Burst {glyphs: Vec::new(), font: &fc, dir: ItemTypesetting(DirBehavior(Forward, Perpendicular), Rot180::Normal), glyph_map: Vec::new()}
	]);
	assert_eq!(res.len(), 3);
	assert_eq!(res[1].glyphs, vec![GlyphIndex(1), GlyphIndex(2)]);
}<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_use] extern crate bitflags;
extern crate libc;

use std::io::{self, Error};
use std::os::unix::io::RawFd;

#[allow(non_camel_case_types)]
pub enum ControlOptions {
    /// Indicates an addition to the interest list.
    EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD as isize,
    /// Indicates a modification of flags for an interest already in list.
    EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD as isize,
    /// Indicates a removal of an interest from the list.
    EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL as isize
}

bitflags! {
    pub struct Events: u32 {
        /// Sets the Edge Triggered behavior for the associated file descriptor.
        ///
        /// The default behavior for epoll is Level Triggered.
        const EPOLLET      = libc::EPOLLET as u32;
        /// The associated file is available for read operations.
        const EPOLLIN      = libc::EPOLLIN as u32;
        /// Error condition happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; is not necessary to set it in events.
        const EPOLLERR     = libc::EPOLLERR as u32;
        /// Hang up happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; it is not necessary to set it in events.
        /// Note that when reading from a channel such as a pipe or a stream socket, this event
        /// merely indicates that the peer closed its end of the channel. Subsequent reads from
        /// the channel will return 0 (end of file) only after all outstanding data in the
        /// channel has been consumed.
        const EPOLLHUP     = libc::EPOLLHUP as u32;
        /// The associated file is available for write operations.
        const EPOLLOUT     = libc::EPOLLOUT as u32;
        /// There is urgent data available for read operations.
        const EPOLLPRI     = libc::EPOLLPRI as u32;
        /// Stream socket peer closed connection, or shut down writing half of connection.
        ///
        /// This flag is especially useful for writing simple code to detect peer shutdown when
        /// using Edge Triggered monitoring.
        const EPOLLRDHUP   = libc::EPOLLRDHUP as u32;
        /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND`
        /// capability, ensure that the system does not enter "suspend" or "hibernate" while this
        /// event is pending or being processed.
        ///
        /// The event is considered as being "processed" from the time when it is returned by
        /// a call to `wait` until the next call to `wait` on the same `EpollInstance`
        /// descriptor, the closure of that file descriptor, the removal of the event file
        /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file
        /// descriptor with `EPOLL_CTL_MOD`.
        const EPOLLWAKEUP  = libc::EPOLLWAKEUP as u32;
        /// Sets the one-shot behavior for the associated file descriptor.
        ///
        /// This means that after an event is pulled out with `wait` the associated file
        /// descriptor is internally disabled and no other events will be reported by the epoll
        /// interface.  The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file
        /// descriptor with a new event mask.
        const EPOLLONESHOT = libc::EPOLLONESHOT as u32;
    }
}

/// 'libc::epoll_event' equivalent.
#[repr(C)]
#[repr(packed)]
#[derive(Clone, Copy)]
pub struct Event {
    pub events: u32,
    pub data: u64
}

impl Event {
    pub fn new(events: Events, data: u64) -> Event {
        Event { events: events.bits(), data: data }
    }
}

/// Creates a new epoll file descriptor.
///
/// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor.
///
/// ## Notes
///
/// * `epoll_create1()` is the underlying syscall.
pub fn create(cloexec: bool) -> io::Result<RawFd> {
    let flags = if cloexec { libc::EPOLL_CLOEXEC } else { 0 };
    unsafe { cvt(libc::epoll_create1(flags)) }
}

/// Safe wrapper for `libc::epoll_ctl`
pub fn ctl(epfd: RawFd,
           op: ControlOptions,
           fd: RawFd,
           mut event: Event)
           -> io::Result<()>
{
    let e = &mut event as *mut _ as *mut libc::epoll_event;
    unsafe { try!(cvt(libc::epoll_ctl(epfd, op as i32, fd, e))) };
    Ok(())
}

/// Safe wrapper for `libc::epoll_wait`
///
/// ## Notes
///
/// * If `timeout` is negative, it will block until an event is received.
pub fn wait(epfd: RawFd,
            timeout: i32,
            buf: &mut [Event])
            -> io::Result<usize>
{
    let timeout = if timeout < -1 { -1 } else { timeout };
    let num_events = unsafe {
        try!(cvt(libc::epoll_wait(epfd,
                                  buf.as_mut_ptr() as *mut libc::epoll_event,
                                  buf.len() as i32,
                                  timeout))) as usize
    };
    Ok(num_events)
}

fn cvt(result: libc::c_int) -> io::Result<libc::c_int> {
    if result < 0 { Err(Error::last_os_error()) } else { Ok(result) }
}
<commit_msg>Fix inconsistency with libc attribute decoration<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_use] extern crate bitflags;
extern crate libc;

use std::io::{self, Error};
use std::os::unix::io::RawFd;

#[allow(non_camel_case_types)]
pub enum ControlOptions {
    /// Indicates an addition to the interest list.
    EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD as isize,
    /// Indicates a modification of flags for an interest already in list.
    EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD as isize,
    /// Indicates a removal of an interest from the list.
    EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL as isize
}

bitflags! {
    pub struct Events: u32 {
        /// Sets the Edge Triggered behavior for the associated file descriptor.
        ///
        /// The default behavior for epoll is Level Triggered.
        const EPOLLET      = libc::EPOLLET as u32;
        /// The associated file is available for read operations.
        const EPOLLIN      = libc::EPOLLIN as u32;
        /// Error condition happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; is not necessary to set it in events.
        const EPOLLERR     = libc::EPOLLERR as u32;
        /// Hang up happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; it is not necessary to set it in events.
        /// Note that when reading from a channel such as a pipe or a stream socket, this event
        /// merely indicates that the peer closed its end of the channel. Subsequent reads from
        /// the channel will return 0 (end of file) only after all outstanding data in the
        /// channel has been consumed.
        const EPOLLHUP     = libc::EPOLLHUP as u32;
        /// The associated file is available for write operations.
        const EPOLLOUT     = libc::EPOLLOUT as u32;
        /// There is urgent data available for read operations.
        const EPOLLPRI     = libc::EPOLLPRI as u32;
        /// Stream socket peer closed connection, or shut down writing half of connection.
        ///
        /// This flag is especially useful for writing simple code to detect peer shutdown when
        /// using Edge Triggered monitoring.
        const EPOLLRDHUP   = libc::EPOLLRDHUP as u32;
        /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND`
        /// capability, ensure that the system does not enter "suspend" or "hibernate" while this
        /// event is pending or being processed.
        ///
        /// The event is considered as being "processed" from the time when it is returned by
        /// a call to `wait` until the next call to `wait` on the same `EpollInstance`
        /// descriptor, the closure of that file descriptor, the removal of the event file
        /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file
        /// descriptor with `EPOLL_CTL_MOD`.
        const EPOLLWAKEUP  = libc::EPOLLWAKEUP as u32;
        /// Sets the one-shot behavior for the associated file descriptor.
        ///
        /// This means that after an event is pulled out with `wait` the associated file
        /// descriptor is internally disabled and no other events will be reported by the epoll
        /// interface.  The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file
        /// descriptor with a new event mask.
        const EPOLLONESHOT = libc::EPOLLONESHOT as u32;
    }
}

/// 'libc::epoll_event' equivalent.
#[repr(C)]
#[cfg_attr(target_arch = "x86_64", repr(packed))]
#[derive(Clone, Copy)]
pub struct Event {
    pub events: u32,
    pub data: u64
}

impl Event {
    pub fn new(events: Events, data: u64) -> Event {
        Event { events: events.bits(), data: data }
    }
}

/// Creates a new epoll file descriptor.
///
/// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor.
///
/// ## Notes
///
/// * `epoll_create1()` is the underlying syscall.
pub fn create(cloexec: bool) -> io::Result<RawFd> {
    let flags = if cloexec { libc::EPOLL_CLOEXEC } else { 0 };
    unsafe { cvt(libc::epoll_create1(flags)) }
}

/// Safe wrapper for `libc::epoll_ctl`
pub fn ctl(epfd: RawFd,
           op: ControlOptions,
           fd: RawFd,
           mut event: Event)
           -> io::Result<()>
{
    let e = &mut event as *mut _ as *mut libc::epoll_event;
    unsafe { try!(cvt(libc::epoll_ctl(epfd, op as i32, fd, e))) };
    Ok(())
}

/// Safe wrapper for `libc::epoll_wait`
///
/// ## Notes
///
/// * If `timeout` is negative, it will block until an event is received.
pub fn wait(epfd: RawFd,
            timeout: i32,
            buf: &mut [Event])
            -> io::Result<usize>
{
    let timeout = if timeout < -1 { -1 } else { timeout };
    let num_events = unsafe {
        try!(cvt(libc::epoll_wait(epfd,
                                  buf.as_mut_ptr() as *mut libc::epoll_event,
                                  buf.len() as i32,
                                  timeout))) as usize
    };
    Ok(num_events)
}

fn cvt(result: libc::c_int) -> io::Result<libc::c_int> {
    if result < 0 { Err(Error::last_os_error()) } else { Ok(result) }
}
<|endoftext|>


<commit_before>#![crate_name="mockstream"]
#![crate_type="lib"]
//! A reader/writer streams to mock real streams in tests.

use std::rc::{Rc};
use std::cell::{RefCell};
use std::io::{Cursor,Read,Write,Result};
use std::mem::swap;

#[cfg(test)]
mod tests;

/// MockStream is Read+Write stream that stores the data written and provides the data to be read.
pub struct MockStream {
	reader: Cursor<Vec<u8>>,
	writer: Cursor<Vec<u8>>,
}

fn new_cursor() -> Cursor<Vec<u8>> {
	Cursor::new(Vec::new())
}

impl MockStream {
	/// Create new empty stream
	pub fn new() -> MockStream {
		MockStream {
			reader: new_cursor(),
			writer: new_cursor(),
		}
	}

	/// Extract all bytes written by Write trait calls.
	pub fn pop_bytes_written(&mut self) -> Vec<u8> {
		let mut result = Vec::new();
		swap(&mut result, self.writer.get_mut());
		result
	}

	/// Provide data to be read by Read trait calls.
	pub fn push_bytes_to_read(&mut self, bytes: &[u8]) {
		let avail = self.reader.get_ref().len();
		if self.reader.position() == avail as u64 {
			self.reader = new_cursor();
		}
		self.reader.get_mut().extend(bytes.iter().map(|c| *c));
	}
}

impl Read for MockStream {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		self.reader.read(buf)
	}
}

impl Write for MockStream {
	fn write<'a>(&mut self, buf: &'a [u8]) -> Result<usize> {
		self.writer.write(buf)
	}

	fn flush(&mut self) -> Result<()> {
		self.writer.flush()
	}
}

/// Reference-counted stream.
#[derive(Clone)]
pub struct SharedMockStream {
	pimpl: Rc<RefCell<MockStream>>
}

impl SharedMockStream {
	/// Create empty stream
	pub fn new() -> SharedMockStream {
		SharedMockStream { pimpl: Rc::new(RefCell::new(MockStream::new())) }
	}

	/// Extract all bytes written by Write trait calls.
	pub fn push_bytes_to_read(&mut self, bytes: &[u8]) {
		self.pimpl.borrow_mut().push_bytes_to_read(bytes)
	}

	/// Provide data to be read by Read trait calls.
	pub fn pop_bytes_written(&mut self) -> Vec<u8> {
		self.pimpl.borrow_mut().pop_bytes_written()
	}
}

impl Read for SharedMockStream {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		self.pimpl.borrow_mut().read(buf)
	}
}

impl Write for SharedMockStream {
	fn write(&mut self, buf: &[u8]) -> Result<usize> {
		self.pimpl.borrow_mut().write(buf)
	}

	fn flush(&mut self) -> Result<()> {
		self.pimpl.borrow_mut().flush()
	}
}
<commit_msg>Derive Clone for MockStream<commit_after>#![crate_name="mockstream"]
#![crate_type="lib"]
//! A reader/writer streams to mock real streams in tests.

use std::rc::{Rc};
use std::cell::{RefCell};
use std::io::{Cursor,Read,Write,Result};
use std::mem::swap;

#[cfg(test)]
mod tests;

/// MockStream is Read+Write stream that stores the data written and provides the data to be read.
#[derive(Clone)]
pub struct MockStream {
	reader: Cursor<Vec<u8>>,
	writer: Cursor<Vec<u8>>,
}

fn new_cursor() -> Cursor<Vec<u8>> {
	Cursor::new(Vec::new())
}

impl MockStream {
	/// Create new empty stream
	pub fn new() -> MockStream {
		MockStream {
			reader: new_cursor(),
			writer: new_cursor(),
		}
	}

	/// Extract all bytes written by Write trait calls.
	pub fn pop_bytes_written(&mut self) -> Vec<u8> {
		let mut result = Vec::new();
		swap(&mut result, self.writer.get_mut());
		result
	}

	/// Provide data to be read by Read trait calls.
	pub fn push_bytes_to_read(&mut self, bytes: &[u8]) {
		let avail = self.reader.get_ref().len();
		if self.reader.position() == avail as u64 {
			self.reader = new_cursor();
		}
		self.reader.get_mut().extend(bytes.iter().map(|c| *c));
	}
}

impl Read for MockStream {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		self.reader.read(buf)
	}
}

impl Write for MockStream {
	fn write<'a>(&mut self, buf: &'a [u8]) -> Result<usize> {
		self.writer.write(buf)
	}

	fn flush(&mut self) -> Result<()> {
		self.writer.flush()
	}
}

/// Reference-counted stream.
#[derive(Clone)]
pub struct SharedMockStream {
	pimpl: Rc<RefCell<MockStream>>
}

impl SharedMockStream {
	/// Create empty stream
	pub fn new() -> SharedMockStream {
		SharedMockStream { pimpl: Rc::new(RefCell::new(MockStream::new())) }
	}

	/// Extract all bytes written by Write trait calls.
	pub fn push_bytes_to_read(&mut self, bytes: &[u8]) {
		self.pimpl.borrow_mut().push_bytes_to_read(bytes)
	}

	/// Provide data to be read by Read trait calls.
	pub fn pop_bytes_written(&mut self) -> Vec<u8> {
		self.pimpl.borrow_mut().pop_bytes_written()
	}
}

impl Read for SharedMockStream {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		self.pimpl.borrow_mut().read(buf)
	}
}

impl Write for SharedMockStream {
	fn write(&mut self, buf: &[u8]) -> Result<usize> {
		self.pimpl.borrow_mut().write(buf)
	}

	fn flush(&mut self) -> Result<()> {
		self.pimpl.borrow_mut().flush()
	}
}
<|endoftext|>


<commit_before>//! This crate is a small wrapper around the [buerostatus](https://github.com/fsr/buerostatus) API
//! of the [@fsr](https://github.com/fsr) that tells you whether someone is in our office or not.
//!
//! # Example
//! ```
//! # use buerostatus::*;
//! if let Ok(is_open) = get_buerostatus() {
//!     if is_open { println!("Someone's inside!"); }
//!     else { println!("No one is there..."); }
//! }
//! else {
//!     println!("An error occured!");
//! }
//! ```
//!
//! The function `get_buerostatus()` offers a precise error message in case of an error. See the enum
//! `ApiError` for more information.

extern crate reqwest;

//use reqwest;
use reqwest::Error;
use reqwest::StatusCode;
use std::io::Read;

/// A set of errors that may occur during the API call.
#[derive(Debug)]
pub enum ApiError {
    /// An error originating from the `reqwest` crate such as "No Internet connection".
    Network(reqwest::HyperError),
    /// The Return Code of the website is not _200_.
    StatusNotOk(reqwest::StatusCode),
    /// The API call delivered a wrong message.
    WrongMessage
}

/// Gets the buerostatus from ifsr.de.
///
/// Returns `true`, when the office is open, `false` if not and an `ApiError` if any form of error is occured during execution.
///
/// # Example
/// ```
/// # use buerostatus::*;
/// if let Ok(is_open) = get_buerostatus() {
///     if is_open {
///         println!("Someone's inside!");
///     }
/// }
/// else {
///     // Error Handling...
/// }
/// ```
pub fn get_buerostatus() -> Result<bool, ApiError> {
    let url = "https://www.ifsr.de/buerostatus/output.php";

    // Make the request to ifsr.de
    let mut res = match reqwest::get(url) {
        Ok(resp)                => resp,
        Err(Error::Http(err))   => return Err(ApiError::Network(err)),
        Err(_)                  => return Err(ApiError::WrongMessage),     // TODO: Replace me!
    };

    // Check if response from Server is Status 200.
    if *res.status() != StatusCode::Ok {
        return Err(ApiError::StatusNotOk(*res.status()));
    }

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

    // Check the content of the response
    match message.as_ref() {
        "0" => Ok(false),
        "1" => Ok(true),
        _   => Err(ApiError::WrongMessage), // just in case, the server _should_ always return 1 or 0.
    }
}
<commit_msg>generalized network errors<commit_after>//! This crate is a small wrapper around the [buerostatus](https://github.com/fsr/buerostatus) API
//! of the [@fsr](https://github.com/fsr) that tells you whether someone is in our office or not.
//!
//! # Example
//! ```
//! # use buerostatus::*;
//! if let Ok(is_open) = get_buerostatus() {
//!     if is_open { println!("Someone's inside!"); }
//!     else { println!("No one is there..."); }
//! }
//! else {
//!     println!("An error occured!");
//! }
//! ```
//!
//! The function `get_buerostatus()` offers a precise error message in case of an error. See the enum
//! `ApiError` for more information.

extern crate reqwest;

use reqwest::StatusCode;
use std::io::Read;

/// A set of errors that may occur during the API call.
#[derive(Debug)]
pub enum ApiError {
    /// An error originating from the `reqwest` crate such as "No Internet connection".
    Network(reqwest::Error),
    /// The Return Code of the website is not _200_.
    StatusNotOk(reqwest::StatusCode),
    /// The API call delivered a wrong message.
    WrongMessage
}

/// Gets the buerostatus from ifsr.de.
///
/// Returns `true`, when the office is open, `false` if not and an `ApiError` if any form of error is occured during execution.
///
/// # Example
/// ```
/// # use buerostatus::*;
/// if let Ok(is_open) = get_buerostatus() {
///     if is_open {
///         println!("Someone's inside!");
///     }
/// }
/// else {
///     // Error Handling...
/// }
/// ```
pub fn get_buerostatus() -> Result<bool, ApiError> {
    let url = "https://www.ifsr.de/buerostatus/output.php";

    // Make the request to ifsr.de
    let mut res = match reqwest::get(url) {
        Ok(resp)    => resp,
        Err(err)    => return Err(ApiError::Network(err))
    };

    // Check if response from Server is Status 200.
    if *res.status() != StatusCode::Ok {
        return Err(ApiError::StatusNotOk(*res.status()));
    }

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

    // Check the content of the response
    match message.as_ref() {
        "0" => Ok(false),
        "1" => Ok(true),
        _   => Err(ApiError::WrongMessage), // just in case, the server _should_ always return 1 or 0.
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Benjamin Fry <benjaminfry@me.com>

use std::ascii::AsciiExt;

/// returns true if and only if the phrase is a palindrome
///
/// # Arguments
///
/// `phrase` - the phrase to inspect
///
/// This is just to be fun with iterators...
pub fn is_palindrome(phrase: &str) -> bool {
    println!("phrase: {}", phrase);
    // remove all none alphabetic characters
    let chars: Vec<char> = phrase.chars().filter(|c| c.is_alphabetic()).collect();
    let half = (chars.len() as f32 / 2f32).ceil() as usize;

    // take the first half
    chars.iter().take(half)
                // zip with the second half...
                .zip(chars.iter()
                          // which needs to be reversed...
                          .rev()
                          // take the last half
                          .take(half))
                // check that all the chars from the begining and end match
                .all(|(first_char, last_char)| {
                    first_char.to_ascii_lowercase() == last_char.to_ascii_lowercase()
                })
}

#[test]
fn test_is_palindrome() {
    assert!(is_palindrome(""));
    assert!(is_palindrome("A man, a plan, a canal, Panama!"));
    assert!(is_palindrome("Amor, Roma"));
    assert!(is_palindrome("race car"));
    assert!(is_palindrome("stack cats"));
    assert!(is_palindrome("step on no pets"));
    assert!(is_palindrome("taco cat"));
    assert!(is_palindrome("put it up"));
    assert!(is_palindrome("Was it a car or a cat I saw?"));
    assert!(is_palindrome("No ‘x’ in Nixon"));

    // negative for good messure
    assert!(!is_palindrome("Not a palindrome"))
}
<commit_msg>added a classic array based palindrome<commit_after>// Copyright (C) 2016 Benjamin Fry <benjaminfry@me.com>

use std::ascii::AsciiExt;

/// returns true if and only if the phrase is a palindrome
///
/// # Arguments
///
/// * `phrase` - the phrase to inspect
///
/// This is just to be fun with iterators...
/// This should be O(2n), and would be fewer lines without all the comments.
pub fn is_palindrome(phrase: &str) -> bool {
    // remove all none alphabetic characters
    let chars: Vec<char> = phrase.chars().filter(|c| c.is_alphabetic()).collect();
    let half = (chars.len() as f32 / 2f32).ceil() as usize;

    // take the first half
    chars.iter().take(half)
                // zip with the second half...
                .zip(chars.iter()
                          // which needs to be reversed...
                          .rev()
                          // take the last half
                          .take(half))
                // check that all the chars from the begining and end match
                .all(|(first_char, last_char)| {
                    first_char.to_ascii_lowercase() == last_char.to_ascii_lowercase()
                })
}

/// this is a class array implementation (for comparison)
///
/// # Arguments
///
/// * `phrase` - the phrase to inspect
///
/// This is definitely not the most efficient, but is meant show the difference to above. And be
///  close to the semantics used in C/C++, with the exception of the chars().collect() this should
///  be O(2n) like above.
pub fn is_palindrome_classic(phrase: &str) -> bool {
    // remove all none alphabetic characters
    let mut chars: Vec<char> = Vec::with_capacity(phrase.len());

    // specifically not using some of Rust's nice features for this copy
    //  but need to use the iterator b/c the std library is removing direct access to the chars
    //  i.e. there are better ways to do this ;)
    let phrase: Vec<char> = phrase.chars().collect();
    for i in 0..phrase.len() {
        // annoyingly traking a separate index
        let c = phrase[i];
        // ok, using push, but still...
        if c.is_alphabetic() { chars.push(c) }
    }

    let half = (chars.len() as f32 / 2f32).ceil() as usize;

    // now do the looping comparison
    for i in 0..half {
        // ug, indexes
        if chars[i].to_ascii_lowercase() !=
           // here's a classic off by one error you don't get in the iterator model
           chars[chars.len() - i - 1].to_ascii_lowercase() { return false }
    }

    // is this actually simpler or more readable? I don't think so...

    true
}

#[test]
fn test_is_palindrome() {
    test_is_palindrome_base(is_palindrome);
}

#[test]
fn test_palindrome_classic() {
    test_is_palindrome_base(is_palindrome_classic);
}

#[cfg(test)]
fn test_is_palindrome_base<F>(is_palindrome: F) where F: Fn(&str) -> bool {
    assert!(is_palindrome(""));
    assert!(is_palindrome("A man, a plan, a canal, Panama!"));
    assert!(is_palindrome("Amor, Roma"));
    assert!(is_palindrome("race car"));
    assert!(is_palindrome("stack cats"));
    assert!(is_palindrome("step on no pets"));
    assert!(is_palindrome("taco cat"));
    assert!(is_palindrome("put it up"));
    assert!(is_palindrome("Was it a car or a cat I saw?"));
    assert!(is_palindrome("No ‘x’ in Nixon"));

    // negative for good messure
    assert!(!is_palindrome("Not a palindrome"))
}
<|endoftext|>


<commit_before>//
// yaml.rs
// Nothing to see here yet
//

#![crate_id="yaml"]

use std::iter::Iterator;
use std::option::Option;
use std::io::IoResult;
use self::Token::*;

/// A Yaml Tokenizer
///
/// A tokenizer takes a byte stream and produces a stream of Tokens
/// This shelters the parser from the complexity of dealing with raw bytes.
///
pub struct Tokenizer<'a> {
    reader: Box<Reader + 'a>,
    buffer: Vec<u8>,
    position: usize,
    peek: usize,
    done: bool,
}

impl <'a>Tokenizer<'a> {

    /// Creates a new Tokenizer from a Reader
    pub fn new<T: Reader + 'a>(reader: Box<T>) -> Tokenizer<'a> {
        Tokenizer {
            reader: reader,
            done: false,
            buffer: Vec::new(),
            position: 0,
            peek: 0,
        }
    }

    /// Gets the next byte
    pub fn get_byte(&mut self) -> IoResult<u8> {

        // If the buffer is empty, fill it
        if self.peek == self.buffer.len() {
            match self.reader.read_byte() {
                Ok(byte) => {
                    self.buffer.push(byte);
                    Ok(byte)
                },
                Err(error) => {
                    Err(error)
                }
            }
        } else {
            Ok(self.buffer[self.peek])
        }
    }

    pub fn peek(&mut self) -> IoResult<u8> {
        let byte = self.get_byte();
        match byte {
            Ok(_) => { self.peek += 1 },
            _ => {},
        }
        byte
    }

    pub fn advance(&mut self, number: usize) {
        self.position += number;
        self.peek = self.position;
    }

    /// Gets the next token in the stream
    pub fn get_next_token(&mut self) -> Option<Token> {
        if self.done {
            return None;
        }

        let token = match self.peek() {

            // TODO: Check error value
            Err(_) => {
                self.done = true;
                Token::Eof
            },
            Ok(byte) => {
                match byte as char {

                    // Indicators:
                    '[' => {
                        self.advance(1);
                        SequenceStart
                    },
                    ']' => {
                        self.advance(1);
                        SequenceEnd
                    },
                    '{' => {
                        self.advance(1);
                        MappingStart
                    },
                    '}' =>  {
                        self.advance(1);
                        MappingEnd
                    },
                    '-' => {
                        if self.check_document_start() {
                            self.advance(3);
                            DocumentStart
                        } else {
                            self.advance(1);
                            SequenceEntry
                        }
                    },
                    '.' => {
                        if self.check_document_end() {
                            self.advance(3);
                            DocumentEnd
                        } else {
                            Other
                        }
                    },
                    ':' => MappingSeparator,
                    ',' => CollectionSeparator,
                    '?' => ComplexKey,
                    '!' => Tag,
                    '&' => Anchor,
                    '*' => Alias,
                    '|' => Literal,
                    '>' => Folded,
                    '\'' => SingleQuote,
                    '"' => DoubleQuote,
                    '#' => Comment,
                    '%' => Directive,
                    '@' | '`' => Reserved,
                    _ => Other,
                }
            }
        };

        Some(token)
    }

    fn check_document_start(&mut self) -> bool {
        match (self.peek(), self.peek()) {
            (Ok(byte1), Ok(byte2)) => {
                byte1 as char == '-' && byte2 as char == '-'
            },
            _ => false
        }
    }

    fn check_document_end(&mut self) -> bool {
        match (self.peek(), self.peek()) {
            (Ok(byte1), Ok(byte2)) => {
                byte1 as char == '.' && byte2 as char == '.'
            },
            _ => false
        }
    }
}

/// All the types of tokens
///
/// Describes all of the token types described by the [Yaml 1.0 Spec](http://yaml.org/spec/1.0/)
///
#[derive(PartialEq, Copy, Debug)]
pub enum Token {

    /// `[`: the start of a _flow_ sequence
    /// `c-sequence-start` in the spec
    SequenceStart,

    /// `]`: the end of a _flow_ sequence
    /// `c-sequence-end` in the spec
    SequenceEnd,

    /// `{`: the end of a _flow_ mapping
    /// `c-mapping-start` in the spec
    MappingStart,

    /// `}`: the end of a _flow_ mapping
    /// `c-mapping-end` in the spec
    MappingEnd,

    /// `-`: indicates an entry in a sequence
    /// `c-sequence-entry` in the spec
    SequenceEntry,

    /// `:`: separates key from value in a mapping
    /// `c-mapping-entry` in the spec
    MappingSeparator,

    /// `,`: separates entries in _flow_ collections (mapping or sequence)
    /// `c-collect-entry` in the spec
    CollectionSeparator,

    /// `?`: indicates a complex key (e.g a non-scalar key)
    /// `c-complex-key` in the spec
    ComplexKey,

    /// `!`: indicates a tag property
    /// `c-tag` in the spec
    Tag,

    /// `&`: indicates an anchor property (e.g setting a variable)
    /// `c-anchor` in the spec
    Anchor,

    /// `*`: indicates an anchor property (e.g using a variable)
    /// `c-alias` in the spec
    Alias,

    /// `|`: indicates a literal value (not to be escaped)
    /// `c-literal` in the spec
    Literal,

    /// `>`: indicates a folded value (ignore line breaks)
    /// `c-folded` in the spec
    Folded,

    /// `'`: a single quoted scalar
    /// `c-single-quote` in the spec
    SingleQuote,

    /// `"`: a double quoted scalar
    /// `c-double-quote` in the spec
    DoubleQuote,

    /// `#`: a comment
    /// `c-throwaway`
    Comment,

    /// `%`: a directive (tags for the YAML parser)
    /// `c-directive` in the spec
    Directive,

    /// `@ | \``: reserved for future use?
    /// `c-reserved` in the spec
    Reserved,

    ///TODO Documentation
    ///
    DocumentStart,

    ///TODO: Documentation
    ///
    DocumentEnd,

    /// ``: a line break with no specific purpose
    LineBreakGeneric,

    /// ``
    LineBreak(LineBreakType),

    Other, // A temporary addition for unimplemented tokens
    Eof,
}

#[derive(PartialEq, Copy, Debug)]
pub enum LineBreakType {
    Generic,
    LineSeparator,
    ParagraphSeparator
}

impl <'a>Iterator for Tokenizer<'a> {

    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.get_next_token()
    }
}

mod test {

    use std::io::MemReader;
    use std::vec;

    use super::{Tokenizer, Token};
    use super::Token::*;

    #[test]
    fn test_scanner() {
        let stream = "---[]-...";
        let mut reader = MemReader::new(stream.bytes().collect());
        let mut tokenizer = Tokenizer::new(Box::new(reader));
        let tokens: Vec<Token> = tokenizer.collect();

        assert!(tokens == vec![DocumentStart, SequenceStart, SequenceEnd, SequenceEntry, DocumentEnd, Eof]);
    }
}
<commit_msg>Refactor operation<commit_after>//
// yaml.rs
// Nothing to see here yet
//

#![crate_id="yaml"]

use std::iter::Iterator;
use std::option::Option;
use std::io::{IoResult, MemReader};
use std::borrow::Cow;
use self::Token::*;

/// A Yaml Tokenizer
///
/// A tokenizer takes a byte stream and produces a stream of Tokens
/// This shelters the parser from the complexity of dealing with raw bytes.
///
pub struct Tokenizer<'a> {
    reader: Box<Reader + 'a>,
    stack: Vec<u8>,
}

impl <'a>Tokenizer<'a> {

    /// Creates a new Tokenizer from a Reader
    pub fn new<T: Reader + 'a>(reader: Box<T>) -> Tokenizer<'a> {
        Tokenizer {
            reader: reader,
            stack: Vec::new(),
        }
    }

    fn read_char(&mut self) -> Option<char> {
        match self.reader.read_byte() {
            Ok(byte) => Some(byte as char),
            Err(_) => None,
        }
    }

    pub fn pop(&mut self) -> Option<char> {
        if(self.stack.len() == 0) {
            self.read_char()
        } else {
            match self.stack.pop() {
                Some(byte) => Some(byte as char),
                None => None,
            }
        }
    }

    pub fn next_token(&mut self) -> Option<Token> {
        match self.pop() {
            Some(character) => match character {
                '-' => {
                    if self.consume("--") {
                        Some(DocumentStart)
                    } else {
                        Some(SequenceEntry)
                    }
                },
                _ => {
                    self.stack.push(character as u8);
                    self.consume_scalar()
                },
            },
            None => None,
        }
    }

    fn consume_scalar(&mut self) -> Option<Token> {
        let mut eaten = Vec::new();
        loop {
            match self.pop() {
                Some(character) => match character {
                    'A'...'Z'|'a'...'z'|'0'...'9' => {
                        eaten.push(character as u8);
                    },
                    _ => {
                        self.stack.push(character as u8);
                        break;
                    },
                },
                None => {
                    break;
                }
            }
        }

        match String::from_utf8(eaten) {
            Ok(string) => Some(Scalar(string)),
            Err(_) => None,
        }
    }

    fn consume(&mut self, edible: &'static str) -> bool {
        let mut eaten = Vec::new();
        for expected in edible.chars() {
            let character = self.pop();
            if character.is_some() {
                let c = character.unwrap();
                eaten.push(c as u8);
                if c == expected {
                    continue;
                }
            }
            for ate in eaten.drain().rev() {
                self.stack.push(ate);
            }
            return false;
        }
        true
    }
}

/// All the types of tokens
///
/// Describes all of the token types described by the [Yaml 1.0 Spec](http://yaml.org/spec/1.0/)
///
#[derive(PartialEq, Debug)]
pub enum Token {

    /// `[`: the start of a _flow_ sequence
    /// `c-sequence-start` in the spec
    SequenceStart,

    /// `]`: the end of a _flow_ sequence
    /// `c-sequence-end` in the spec
    SequenceEnd,

    /// `{`: the end of a _flow_ mapping
    /// `c-mapping-start` in the spec
    MappingStart,

    /// `}`: the end of a _flow_ mapping
    /// `c-mapping-end` in the spec
    MappingEnd,

    /// `-`: indicates an entry in a sequence
    /// `c-sequence-entry` in the spec
    SequenceEntry,

    /// `:`: separates key from value in a mapping
    /// `c-mapping-entry` in the spec
    MappingSeparator,

    /// `,`: separates entries in _flow_ collections (mapping or sequence)
    /// `c-collect-entry` in the spec
    CollectionSeparator,

    /// `?`: indicates a complex key (e.g a non-scalar key)
    /// `c-complex-key` in the spec
    ComplexKey,

    /// `!`: indicates a tag property
    /// `c-tag` in the spec
    Tag,

    /// `&`: indicates an anchor property (e.g setting a variable)
    /// `c-anchor` in the spec
    Anchor(String),

    /// `*`: indicates an anchor property (e.g using a variable)
    /// `c-alias` in the spec
    Alias,

    /// `|`: indicates a literal value (not to be escaped)
    /// `c-literal` in the spec
    Literal,

    /// `>`: indicates a folded value (ignore line breaks)
    /// `c-folded` in the spec
    Folded,

    /// `'`: a single quoted scalar
    /// `c-single-quote` in the spec
    SingleQuote,

    /// `"`: a double quoted scalar
    /// `c-double-quote` in the spec
    DoubleQuote,

    /// `#`: a comment
    /// `c-throwaway`
    Comment,

    /// `%`: a directive (tags for the YAML parser)
    /// `c-directive` in the spec
    Directive,

    /// `@ | \``: reserved for future use?
    /// `c-reserved` in the spec
    Reserved,

    ///TODO Documentation
    ///
    DocumentStart,

    ///TODO: Documentation
    ///
    DocumentEnd,

    /// ``: a line break with no specific purpose
    LineBreakGeneric,

    /// ``
    LineBreak(LineBreakType),

    Other, // A temporary addition for unimplemented tokens
    Scalar(String),
    Eof,
}

#[derive(PartialEq, Copy, Debug)]
pub enum LineBreakType {
    Generic,
    LineSeparator,
    ParagraphSeparator
}

impl <'a>Iterator for Tokenizer<'a> {

    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.next_token()
    }
}

fn main() {
    let stream = "--hallo";
    let mut reader = MemReader::new(stream.bytes().collect());
    let mut tokenizer = Tokenizer::new(Box::new(reader));
    let tokens: Vec<Token> = tokenizer.collect();
    println!("{:?}", tokens);
}

<|endoftext|>