<commit_before>extern crate libc;

use std::fs::{OpenOptions, File};
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::{AsRawFd, IntoRawFd, FromRawFd};
use std::ffi::{CStr, CString};
use std::io::{self, Write, Read};
use std::process::{Command, Stdio};
use std::os::unix::process::CommandExt;
use std::ops;

pub struct Pty {
    master: File
}

#[derive(Debug)]
pub enum PtyError {
    OpenPty,
    SpawnShell,
}

pub struct WinSize {
    pub width:  u16,
    pub height: u16,
}

impl WinSize {
    fn to_c_winsize(&self) -> libc::winsize {
        libc::winsize {
            ws_row:    self.width,
            ws_col:    self.height,
            // Unused
            ws_xpixel: 0,
            // Unused
            ws_ypixel: 0,
        }
    }
}

type RawFd = libc::c_int;

impl Pty {
    pub fn spawn(shell: &str, size: &WinSize) -> Result<Pty, PtyError> {
        let (master_fd, tty_path) = getpty(&size)?;
        let (stdin, stdout, stderr) = slave_stdio(&tty_path)?;

        let result = Command::new(&shell)
            .stdin(unsafe  { Stdio::from_raw_fd(stdin.as_raw_fd()) })
            .stdout(unsafe { Stdio::from_raw_fd(stdout.as_raw_fd()) })
            .stderr(unsafe { Stdio::from_raw_fd(stderr.as_raw_fd()) })
            .before_exec(before_exec)
            .spawn();

        match result {
            Ok(mut process) => {
                drop(stdin);
                drop(stdout);
                drop(stderr);
                Ok(Pty {
                    master: unsafe { File::from_raw_fd(master_fd) }
                })
            },
            Err(_) => Err(PtyError::SpawnShell)
        }
    }
}

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

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

    fn flush(&mut self) -> io::Result<()> {
        self.master.flush()
    }
}

impl ops::Deref for Pty {
    type Target = File;

    fn deref(&self) -> &File {
        &self.master
    }
}

impl ops::DerefMut for Pty {
    fn deref_mut(&mut self) -> &mut File {
        &mut self.master
    }
}

trait FromLibcResult: Sized {
    fn to_result(self) -> Result<Self, ()>;
}

impl FromLibcResult for libc::c_int {
    fn to_result(self) -> Result<Self, ()> {
        match self {
            -1  => Err(()),
            res => Ok(res),
        }
    }
}

fn getpty(size: &WinSize) -> Result<(RawFd, String), PtyError> {
    let master_fd = OpenOptions::new()
            .read(true)
            .write(true)
            .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
            .open("/dev/ptmx")
            .map_err(|_| PtyError::OpenPty)?
            .into_raw_fd();

    unsafe {
        libc::grantpt(master_fd)
            .to_result()
            .map_err(|_| PtyError::OpenPty)?;

        libc::unlockpt(master_fd)
            .to_result()
            .map_err(|_| PtyError::OpenPty)?;

        libc::ioctl(master_fd, libc::TIOCSWINSZ, &size.to_c_winsize())
            .to_result()
            .map_err(|_| PtyError::OpenPty)?;
    }

    let tty_path = unsafe { CStr::from_ptr(libc::ptsname(master_fd)).to_string_lossy().into_owned() };
    Ok((master_fd, tty_path))
}

fn slave_stdio(tty_path: &str) -> Result<(File, File, File), PtyError> {
    let tty_c = CString::new(tty_path).unwrap();

    let stdin = unsafe { File::from_raw_fd(
        libc::open(tty_c.as_ptr(), libc::O_CLOEXEC | libc::O_RDONLY)
            .to_result()
            .map_err(|_| PtyError::OpenPty)?
    ) };
    let stdout = unsafe { File::from_raw_fd(
        libc::open(tty_c.as_ptr(), libc::O_CLOEXEC | libc::O_WRONLY)
            .to_result()
            .map_err(|_| PtyError::OpenPty)?
    ) };
    let stderr = unsafe { File::from_raw_fd(
        libc::open(tty_c.as_ptr(), libc::O_CLOEXEC | libc::O_WRONLY)
            .to_result()
            .map_err(|_| PtyError::OpenPty)?
    ) };

    Ok((stdin, stdout, stderr))
}

fn before_exec() -> io::Result<()> {
    unsafe {
        libc::setsid()
            .to_result()
            .map_err(|_| io::Error::new(io::ErrorKind::Other, ""))?;

        libc::ioctl(0, libc::TIOCSCTTY, 1)
            .to_result()
            .map_err(|_| io::Error::new(io::ErrorKind::Other, ""))?;
    }

    Ok(())
}

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

    #[test]
    fn can_open_a_shell_with_its_own_pty_and_can_read_and_write_to_its_master_side() {
        // Opening shell and its pty
        let mut pty = Pty::spawn("/bin/sh", &WinSize { width: 100, height: 100 }).unwrap();

        let mut packet = [0; 4096];
        let mut count_read = 0;

        // Reading
        {
            loop {
                match pty.read(&mut packet) {
                    Err(_)    => continue,
                    Ok(0)     => continue,
                    Ok(count) => { count_read = count; break; }
                }
            }

            assert_eq!(2, count_read);

            let output = String::from_utf8_lossy(&packet[..count_read]);
            assert_eq!("$ ", &output);
        }

        // Writing and reading effect
        {
            pty.write_all("exit\n".as_bytes()).unwrap();
            pty.flush().unwrap();

            loop {
                match pty.read(&mut packet) {
                    Err(_)    => continue,
                    Ok(0)     => continue,
                    Ok(count) => { count_read = count; break; }
                }
            }

            assert_eq!(6, count_read);

            let output = String::from_utf8_lossy(&packet[..count_read]);
            assert_eq!("exit\r\n", &output);
        }
    }
}
<commit_msg>Use openpty, make test more general<commit_after>extern crate libc;

use std::fs::{OpenOptions, File};
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::{AsRawFd, IntoRawFd, FromRawFd};
use std::ffi::{CStr, CString};
use std::ptr;
use std::io::{self, Write, Read};
use std::process::{Command, Stdio};
use std::os::unix::process::CommandExt;
use std::ops;

pub struct Pty {
    fd:   RawFd,
    file: File
}

#[derive(Debug)]
pub enum PtyError {
    OpenPty,
    SpawnShell,
    Resize,
}

pub struct WinSize {
    pub width:  u16,
    pub height: u16,
}

impl WinSize {
    fn to_c_winsize(&self) -> libc::winsize {
        libc::winsize {
            ws_row:    self.width,
            ws_col:    self.height,

            // Unused fields in libc::winsize
            ws_xpixel: 0,
            ws_ypixel: 0,
        }
    }
}

type RawFd = libc::c_int;

impl Pty {
    /// Spawns a child process running the given shell executable with the
    /// given size in a newly created pty.
    /// Returns a Pty representing the master side controlling the pty.
    pub fn spawn(shell: &str, size: &WinSize) -> Result<Pty, PtyError> {
        let (master, slave) = openpty(&size)?;

        Command::new(&shell)
            .stdin(unsafe  { Stdio::from_raw_fd(slave) })
            .stdout(unsafe { Stdio::from_raw_fd(slave) })
            .stderr(unsafe { Stdio::from_raw_fd(slave) })
            .before_exec(before_exec)
            .spawn()
            .and_then(|_| {
                let mut pty = Pty {
                    fd:   master,
                    file: unsafe { File::from_raw_fd(master) }
                };

                pty.resize(&size);

                Ok(pty)
            })
            .map_err(|_| PtyError::SpawnShell)
    }

    /// Resize the child pty.
    pub fn resize(&self, size: &WinSize) -> Result<(), PtyError> {
        unsafe {
            libc::ioctl(self.fd, libc::TIOCSWINSZ, &size.to_c_winsize())
                .to_result()
                .map(|_| ())
                .map_err(|_| PtyError::Resize)
        }
    }
}

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

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

    fn flush(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

impl ops::Deref for Pty {
    type Target = File;

    fn deref(&self) -> &File {
        &self.file
    }
}

impl ops::DerefMut for Pty {
    fn deref_mut(&mut self) -> &mut File {
        &mut self.file
    }
}

trait FromLibcResult: Sized {
    fn to_result(self) -> Result<Self, ()>;
}

impl FromLibcResult for libc::c_int {
    fn to_result(self) -> Result<Self, ()> {
        match self {
            -1  => Err(()),
            res => Ok(res),
        }
    }
}

/// Creates a pty with the given size and returns the (master, slave)
/// pair of file descriptors attached to it.
fn openpty(size: &WinSize) -> Result<(RawFd, RawFd), PtyError> {
    let mut master = 0;
    let mut slave  = 0;

    unsafe {
        // Create the pty master / slave pair
        libc::openpty(&mut master,
                      &mut slave,
                      ptr::null_mut(),
                      ptr::null(),
                      &size.to_c_winsize())
            .to_result()
            .map_err(|_| PtyError::OpenPty)?;

        // Configure master to be non blocking
        libc::fcntl(master,
                    libc::F_SETFL,
                    libc::fcntl(master, libc::F_GETFL, 0) | libc::O_NONBLOCK)
            .to_result()
            .map_err(|_| PtyError::OpenPty)?;
    }

    Ok((master, slave))
}

/// Run between the fork and exec calls. So it runs in the cild process
/// before the process is replaced by the program we want to run.
fn before_exec() -> io::Result<()> {
    unsafe {
        // Create a new process group, this process being the master
        libc::setsid()
            .to_result()
            .map_err(|_| io::Error::new(io::ErrorKind::Other, ""))?;

        // Set this process as the controling terminal
        libc::ioctl(0, libc::TIOCSCTTY, 1)
            .to_result()
            .map_err(|_| io::Error::new(io::ErrorKind::Other, ""))?;
    }

    Ok(())
}

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

    #[test]
    fn can_open_a_shell_with_its_own_pty_and_can_read_and_write_to_its_master_side() {
        // Opening shell and its pty
        let mut pty = Pty::spawn("/bin/sh", &WinSize { width: 100, height: 100 }).unwrap();

        // Reading
        assert!(read(&mut pty).ends_with("$ "));

        // Writing and reading effect
        pty.write_all("exit\n".as_bytes()).unwrap();
        pty.flush().unwrap();

        assert!(read(&mut pty).starts_with("exit"));
    }

    fn read(pty: &mut Pty) -> String {
        let mut packet = [0; 4096];
        let count_read;

        loop {
            match pty.read(&mut packet) {
                Err(_)    => continue,
                Ok(0)     => continue,
                Ok(count) => { count_read = count; break; }
            }
        }

        String::from_utf8_lossy(&packet[..count_read]).to_string()
    }
}
<|endoftext|>


<commit_before>#![feature(associated_consts)]

extern crate num;

pub use color::{Color, Hue, Lightness};
pub use stack::Stack;

mod color;
mod command;
mod interpreter;
mod program;
mod stack;
mod util;
<commit_msg>Remove now-unnecessary feature flag<commit_after>extern crate num;

pub use color::{Color, Hue, Lightness};
pub use stack::Stack;

mod color;
mod command;
mod interpreter;
mod program;
mod stack;
mod util;
<|endoftext|>


<commit_before>//! Structs for conversions from XML to JSON
//!
//! # Example
//! ```
//! use xmlJSON::XmlDocument;
//! use std::str::FromStr;
//!
//! let test = "<note type=\"Reminder\">
//!                 test
//!             </note>";
//! let data = XmlDocument::from_str(test);

extern crate xml;
extern crate rustc_serialize;

use std::io::prelude::*;
use xml::reader::{EventReader,XmlEvent};
use std::str::FromStr;
use std::fmt;
use std::io::Cursor;
use rustc_serialize::json;
use std::collections::BTreeMap;

/// An XML Document
#[derive(Debug, Clone)]
pub struct XmlDocument {
    /// Data contained within the parsed XML Document
    pub data: Vec<XmlData>
}

// Print as JSON
impl fmt::Display for XmlDocument {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = String::new();

        for d in self.data.iter() {
            s = format!("{}{}", s, d);
        }

        s.fmt(f)
    }
}

/// An XML Tag
///
/// For exammple:
///
/// ```XML
/// <foo bar="baz">
///     test text
///
/// </foo>
/// ```
#[derive(Debug, Clone)]
pub struct XmlData {
    /// Name of the tag (i.e. "foo")
    pub name: String,
    /// Key-value pairs of the attributes (i.e. ("bar", "baz"))
    pub attributes: Vec<(String, String)>,
    /// Data (i.e. "test text")
    pub data: Option<String>,
    /// Sub elements (i.e. an XML element of "sub")
    pub sub_elements: Vec<XmlData>
}

// Generate indentation
fn indent(size: usize) -> String {
    const INDENT: &'static str = "    ";
    (0..size).map(|_| INDENT)
        .fold(String::with_capacity(size*INDENT.len()), |r, s| r + s)
}

// Get the attributes as a string
fn attributes_to_string(attributes: &[(String, String)]) -> String {
    attributes.iter().fold(String::new(), |acc, &(ref k, ref v)|{
        format!("{} {}=\"{}\"", acc, k , v)
    })
}

// Format the XML data as a string
fn format(data: &XmlData, depth: usize) -> String {
    let sub =
        if data.sub_elements.is_empty() {
            String::new()
        } else {
            let mut sub = "\n".to_string();
            for elmt in data.sub_elements.iter() {
                sub = format!("{}{}", sub, format(elmt, depth + 1));
            }
            sub
        };

    let indt = indent(depth);

    let fmt_data = if let Some(ref d) = data.data {
        format!("\n{}{}", indent(depth+1), d)
    } else {
        "".to_string()
    };

    format!("{}<{}{}>{}{}\n{}</{}>\n", indt, data.name, attributes_to_string(&data.attributes), fmt_data, sub, indt, data.name)
}

impl fmt::Display for XmlData {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", format(self, 0))
    }
}

// Get the XML atributes as a string
fn map_owned_attributes(attrs: Vec<xml::attribute::OwnedAttribute>) -> Vec<(String, String)> {
    attrs.into_iter().map(|attr|{
        let fmt_name = if attr.name.prefix.is_some() {
            format!("{}:{}", attr.name.prefix.unwrap(), attr.name.local_name)
        } else {
            attr.name.local_name.clone()
        };
        (fmt_name, attr.value)
    }).collect()
}

// Parse the data
fn parse(mut data: Vec<XmlEvent>, current: Option<XmlData>, mut current_vec: Vec<XmlData>, trim: bool) -> Result<(Vec<XmlData>, Vec<XmlEvent>), String> {
    if let Some(elmt) = data.pop() {
        match elmt {
            XmlEvent::StartElement{name, attributes, namespace} => {
                let fmt_name = if name.prefix.is_some() {
                    format!("{}:{}", name.prefix.unwrap(), name.local_name)
                } else {
                    name.local_name
                };

                let inner = XmlData{
                    name: fmt_name,
                    attributes: map_owned_attributes(attributes),
                    data: None,
                    sub_elements: Vec::new()
                };

                let (inner, rest) = try!(parse(data, Some(inner), Vec::new(), trim));

                if let Some(mut crnt) = current {
                    crnt.sub_elements.extend(inner);
                    parse(rest, Some(crnt), current_vec, trim)
                } else {
                    current_vec.extend(inner);
                    parse(rest, None, current_vec, trim)
                }
            },
            XmlEvent::Characters(chr) => {
                let chr = if trim { chr.trim().to_string() } else {chr};
                if let Some(mut crnt) = current {
                    crnt.data = Some(chr);
                    parse(data, Some(crnt), current_vec, trim)
                } else {
                    Err("Invalid form of XML doc".to_string())
                }
            },
            XmlEvent::EndElement{name} => {
                let fmt_name = if name.prefix.is_some() {
                    format!("{}:{}", name.prefix.unwrap(), name.local_name)
                } else {
                    name.local_name.clone()
                };
                if let Some(crnt) = current {
                    if crnt.name == fmt_name {
                        current_vec.push(crnt);
                        return Ok((current_vec, data))
                    } else {
                        Err(format!("Invalid end tag: expected {}, got {}", crnt.name, name.local_name))
                    }
                } else {
                    Err(format!("Invalid end tag: {}", name.local_name))
                }
            }
            _ => parse(data, current, current_vec, trim)
        }
    } else {
        if current.is_some() {
            Err("Invalid end tag".to_string())
        } else {
            Ok((current_vec, Vec::new()))
        }
    }
}

impl XmlDocument {
    pub fn from_reader<R>(source : R, trim: bool) -> Result<Self, ParseXmlError> where R : Read {
        let mut parser = EventReader::new(source);
        let mut events : Vec<XmlEvent> = parser.into_iter().map(|x| x.unwrap() ).collect();
        events.reverse();

        parse(events, None, Vec::new(), trim)
            .map(|(data, _)| XmlDocument{ data: data } )
            .map_err(|e| ParseXmlError(e))
    }
}

/// Error when parsing XML
#[derive(Debug, Clone, PartialEq)]
pub struct ParseXmlError(String);

impl fmt::Display for ParseXmlError{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
        write!(f, "Coult not parse string to XML: {}", self.0)
    }
}

// Generate an XML document from a string
impl FromStr for XmlDocument {
    type Err = ParseXmlError;

    fn from_str(s: &str) -> Result<XmlDocument, ParseXmlError> {
        XmlDocument::from_reader(Cursor::new(s.to_string().into_bytes()), true)
    }
}

// Convert the data to an key-value pair of JSON
fn to_kv(data: &XmlData) -> (String, json::Json) {
    use rustc_serialize::json::ToJson;

    let mut map: BTreeMap<String, json::Json> = BTreeMap::new();

    if data.data.is_some(){
        map.insert("_".to_string(), data.data.clone().unwrap().to_json());
    }

    for (k, v) in data.sub_elements.iter().map(|x|{to_kv(x)}){
        let existed = if let Some(it) = map.get_mut(&k) {
            use rustc_serialize::json::Json;
            match it {
                &mut Json::Array(ref mut a) => {
                    a.push(v.to_json());
                },
                n => {
                    let x = vec![n.clone(), v.to_json()];
                    *n = x.to_json();
                }
            }
            true
        } else {
            false
        };

        if !existed {
            map.insert(k.clone(), v.to_json());
        }
    }

    let mut attr : BTreeMap<String, json::Json> = BTreeMap::new();
    for &(ref k, ref v) in data.attributes.iter() {
        let existed = if let Some(it) = attr.get_mut(k) {
            use rustc_serialize::json::Json;
            match it {
                &mut Json::Array(ref mut a) => {
                    a.push(v.to_json());
                },
                n => {
                    let x = vec![n.clone(), v.to_json()];
                    *n = x.to_json();
                }
            }
            true
        } else {
            false
        };

        if !existed {
            attr.insert(k.clone(), v.to_json());
        }
    }

    if !attr.is_empty() {
        map.insert("$".to_string(), attr.to_json());
    }

    (data.name.clone(), map.to_json())
}

impl json::ToJson for XmlDocument {
    fn to_json(&self) -> json::Json {
        let mut map: BTreeMap<String, json::Json> = BTreeMap::new();

        for (k, v) in self.data.iter().map(|x|{to_kv(x)}) {
            map.insert(k, v);
        }

        map.to_json()
    }
}
<commit_msg>Added namespaces<commit_after>//! Structs for conversions from XML to JSON
//!
//! # Example
//! ```
//! use xmlJSON::XmlDocument;
//! use std::str::FromStr;
//!
//! let test = "<note type=\"Reminder\">
//!                 test
//!             </note>";
//! let data = XmlDocument::from_str(test);

extern crate xml;
extern crate rustc_serialize;

use std::io::prelude::*;
use xml::reader::{EventReader,XmlEvent};
use xml::namespace::{self, Namespace};
use xml::attribute::OwnedAttribute;
use xml::name::OwnedName;
use std::str::FromStr;
use std::fmt;
use std::io::Cursor;
use rustc_serialize::json;
use std::collections::BTreeMap;

/// An XML Document
#[derive(Debug, Clone)]
pub struct XmlDocument {
    /// Data contained within the parsed XML Document
    pub data: Vec<XmlData>
}

// Print as JSON
impl fmt::Display for XmlDocument {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = String::new();

        for d in self.data.iter() {
            s = format!("{}{}", s, d);
        }

        s.fmt(f)
    }
}

/// An XML Tag
///
/// For exammple:
///
/// ```XML
/// <foo bar="baz">
///     test text
///     <sub></sub>
/// </foo>
/// ```
#[derive(Debug, Clone)]
pub struct XmlData {
    /// Name of the tag (i.e. "foo")
    pub name: String,
    /// Key-value pairs of the attributes (i.e. ("bar", "baz"))
    pub attributes: Vec<(String, String)>,
    /// Data (i.e. "test text")
    pub data: Option<String>,
    /// Sub elements (i.e. an XML element of "sub")
    pub sub_elements: Vec<XmlData>
}

// Generate indentation
fn indent(size: usize) -> String {
    const INDENT: &'static str = "    ";
    (0..size).map(|_| INDENT)
        .fold(String::with_capacity(size*INDENT.len()), |r, s| r + s)
}

// Get the attributes as a string
fn attributes_to_string(attributes: &[(String, String)]) -> String {
    attributes.iter().fold(String::new(), |acc, &(ref k, ref v)|{
        format!("{} {}=\"{}\"", acc, k , v)
    })
}

// Format the XML data as a string
fn format(data: &XmlData, depth: usize) -> String {
    let sub =
        if data.sub_elements.is_empty() {
            String::new()
        } else {
            let mut sub = "\n".to_string();
            for elmt in data.sub_elements.iter() {
                sub = format!("{}{}", sub, format(elmt, depth + 1));
            }
            sub
        };

    let indt = indent(depth);

    let fmt_data = if let Some(ref d) = data.data {
        format!("\n{}{}", indent(depth+1), d)
    } else {
        "".to_string()
    };

    format!("{}<{}{}>{}{}\n{}</{}>\n", indt, data.name, attributes_to_string(&data.attributes), fmt_data, sub, indt, data.name)
}

impl fmt::Display for XmlData {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", format(self, 0))
    }
}

// Get the XML atributes as a string
fn map_owned_attributes(attrs: Vec<xml::attribute::OwnedAttribute>) -> Vec<(String, String)> {
    attrs.into_iter().map(|attr|{
        let fmt_name = if attr.name.prefix.is_some() {
            format!("{}:{}", attr.name.prefix.unwrap(), attr.name.local_name)
        } else {
            attr.name.local_name.clone()
        };
        (fmt_name, attr.value)
    }).collect()
}

// Parse the data
fn parse(mut data: Vec<XmlEvent>, current: Option<XmlData>, mut current_vec: Vec<XmlData>, trim: bool, current_namespace : Namespace) -> Result<(Vec<XmlData>, Vec<XmlEvent>), String> {
    if let Some(elmt) = data.pop() {
        match elmt {
            XmlEvent::StartElement{name, attributes, namespace} => {
                let fmt_name = if name.prefix.is_some() {
                    format!("{}:{}", name.prefix.unwrap(), name.local_name)
                } else {
                    name.local_name
                };

                let attributes = if namespace == current_namespace {
                    attributes
                } else {
                    let mut attributes = attributes;
                    let n = namespace.clone();
                    let ns = n.into_iter()
                        .filter(|&(k,v)|{
                            (k != namespace::NS_NO_PREFIX) && (v != namespace::NS_EMPTY_URI)
                        })
                        .map(|(k,v)| {
                        OwnedAttribute {
                            name: OwnedName {
                                local_name: k.to_string(),
                                namespace: Some(v.to_string()),
                                prefix: Some("xmlns".to_string())
                            },
                            value: v.to_string()
                        }
                    });
                    attributes.extend(ns);
                    attributes
                };

                let inner = XmlData{
                    name: fmt_name,
                    attributes: map_owned_attributes(attributes),
                    data: None,
                    sub_elements: Vec::new()
                };

                let (inner, rest) = try!(parse(data, Some(inner), Vec::new(), trim, namespace.clone()));

                if let Some(mut crnt) = current {
                    crnt.sub_elements.extend(inner);
                    parse(rest, Some(crnt), current_vec, trim, namespace)
                } else {
                    current_vec.extend(inner);
                    parse(rest, None, current_vec, trim, namespace)
                }
            },
            XmlEvent::Characters(chr) => {
                let chr = if trim { chr.trim().to_string() } else {chr};
                if let Some(mut crnt) = current {
                    crnt.data = Some(chr);
                    parse(data, Some(crnt), current_vec, trim, current_namespace)
                } else {
                    Err("Invalid form of XML doc".to_string())
                }
            },
            XmlEvent::EndElement{name} => {
                let fmt_name = if name.prefix.is_some() {
                    format!("{}:{}", name.prefix.unwrap(), name.local_name)
                } else {
                    name.local_name.clone()
                };
                if let Some(crnt) = current {
                    if crnt.name == fmt_name {
                        current_vec.push(crnt);
                        return Ok((current_vec, data))
                    } else {
                        Err(format!("Invalid end tag: expected {}, got {}", crnt.name, name.local_name))
                    }
                } else {
                    Err(format!("Invalid end tag: {}", name.local_name))
                }
            }
            _ => parse(data, current, current_vec, trim, current_namespace)
        }
    } else {
        if current.is_some() {
            Err("Invalid end tag".to_string())
        } else {
            Ok((current_vec, Vec::new()))
        }
    }
}

impl XmlDocument {
    pub fn from_reader<R>(source : R, trim: bool) -> Result<Self, ParseXmlError> where R : Read {
        let mut parser = EventReader::new(source);
        let mut events : Vec<XmlEvent> = parser.into_iter().map(|x| x.unwrap() ).collect();
        events.reverse();

        parse(events, None, Vec::new(), trim, Namespace::empty())
            .map(|(data, _)| XmlDocument{ data: data } )
            .map_err(|e| ParseXmlError(e))
    }
}

/// Error when parsing XML
#[derive(Debug, Clone, PartialEq)]
pub struct ParseXmlError(String);

impl fmt::Display for ParseXmlError{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
        write!(f, "Coult not parse string to XML: {}", self.0)
    }
}

// Generate an XML document from a string
impl FromStr for XmlDocument {
    type Err = ParseXmlError;

    fn from_str(s: &str) -> Result<XmlDocument, ParseXmlError> {
        XmlDocument::from_reader(Cursor::new(s.to_string().into_bytes()), true)
    }
}

// Convert the data to an key-value pair of JSON
fn to_kv(data: &XmlData) -> (String, json::Json) {
    use rustc_serialize::json::ToJson;

    let mut map: BTreeMap<String, json::Json> = BTreeMap::new();

    if data.data.is_some(){
        map.insert("_".to_string(), data.data.clone().unwrap().to_json());
    }

    for (k, v) in data.sub_elements.iter().map(|x|{to_kv(x)}){
        let existed = if let Some(it) = map.get_mut(&k) {
            use rustc_serialize::json::Json;
            match it {
                &mut Json::Array(ref mut a) => {
                    a.push(v.to_json());
                },
                n => {
                    let x = vec![n.clone(), v.to_json()];
                    *n = x.to_json();
                }
            }
            true
        } else {
            false
        };

        if !existed {
            map.insert(k.clone(), v.to_json());
        }
    }

    let mut attr : BTreeMap<String, json::Json> = BTreeMap::new();
    for &(ref k, ref v) in data.attributes.iter() {
        let existed = if let Some(it) = attr.get_mut(k) {
            use rustc_serialize::json::Json;
            match it {
                &mut Json::Array(ref mut a) => {
                    a.push(v.to_json());
                },
                n => {
                    let x = vec![n.clone(), v.to_json()];
                    *n = x.to_json();
                }
            }
            true
        } else {
            false
        };

        if !existed {
            attr.insert(k.clone(), v.to_json());
        }
    }

    if !attr.is_empty() {
        map.insert("$".to_string(), attr.to_json());
    }

    (data.name.clone(), map.to_json())
}

impl json::ToJson for XmlDocument {
    fn to_json(&self) -> json::Json {
        let mut map: BTreeMap<String, json::Json> = BTreeMap::new();

        for (k, v) in self.data.iter().map(|x|{to_kv(x)}) {
            map.insert(k, v);
        }

        map.to_json()
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate unicase;
extern crate hyper;

use unicase::UniCase;
use iron::prelude::*;
use iron::method::Method;
use iron::method::Method::*;
use iron::status;
use iron::headers::Origin as OriginHeader;
use iron::headers::{AccessControlRequestMethod, AccessControlRequestHeaders,
                    AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlMaxAge,
                    AccessControlAllowMethods, AccessControlAllowCredentials,
                    AccessControlExposeHeaders};
use iron::middleware::{AroundMiddleware, Handler};
use std::collections::HashSet;
use std::iter::FromIterator;
pub use origin::Origin;

mod origin;

/// Specifies which Origins are allowed to access this resource
pub enum AllowedOrigins {
    /// Any Origin is allowed.
    Any {
        /// If set, wildcard ('*') will be used as value
        /// for AccessControlAllowOrigin if possible. If not set,
        /// echoing the incoming Origin will be preferred.
        /// If credentials are allowed, echoing will always be used.
        prefer_wildcard: bool,
    },
    /// Allow a specific set of origins. Allowing for null origins is
    /// not supported. Partly since the Iron cannot parse a null Origin header,
    /// but also due to it being considered bad practice:
    /// https://w3c.github.io/webappsec-cors-for-developers/
    Specific(HashSet<Origin>),
}

impl AllowedOrigins {
    /// Returns the value of AccessControlAllowOrigin
    /// given the specified Origin header in the request. The allow_credentials
    /// flag is supplied since AccessControlAllowOrigin * is forbidden when credentials
    /// are allowed.
    ///
    /// We're not using the iron Origin header to construct an Origin directly, since
    /// we are dependent on url.port_or_known_default() to get the default port. This
    /// method is only available after parsing the Origin header to an URL.
    fn allowed_for(&self, origin_string: &String, allow_credentials: bool) -> Option<String> {
        match Origin::parse(origin_string) {
            Err(_) => None,
            Ok(origin) => {
                match self {
                    &AllowedOrigins::Any { prefer_wildcard } => {
                        if allow_credentials {
                            // Allow credentials does not permit using wildcard
                            Some(origin_string.clone())
                        } else {
                            // Use wildcard if preferred
                            Some(if prefer_wildcard {
                                     "*".to_owned()
                                 } else {
                                     origin_string.clone()
                                 })
                        }
                    }
                    &AllowedOrigins::Specific(ref allowed) => {
                        if allowed.contains(&origin) {
                            Some(origin_string.clone())
                        } else {
                            None
                        }
                    }
                }
            }
        }

    }
}

/// An iron middleware which implements CORS
///
/// Note: Not using `Vec<Header>` to represent
/// headers since the iron `Header`
/// type is representing a `Key=Value` pair and not just the key.
/// In other words, the Header type represents an instance of
/// a HTTP header. What we need here is something representing the
/// type of header. Since the Header trait defines a a method
/// `fn header_name() -> &'static str`, we conclude that Iron uses
/// strings to represent this.
pub struct CorsMiddleware {
    /// The origins which are allowed to access this resource
    pub allowed_origins: AllowedOrigins,
    /// The methods allowed to perform on this resource
    pub allowed_methods: Vec<Method>,
    /// The headers allowed to send to this resource
    pub allowed_headers: Vec<UniCase<String>>,
    /// The headers allowed to read from the response from this resource
    pub exposed_headers: Vec<UniCase<String>>,
    /// Whether to allow clients to send cookies to this resource or not
    pub allow_credentials: bool,
    /// Defines the max cache lifetime for operations allowed on this
    /// resource
    pub max_age_seconds: u32,
}

/// Returns all standard HTTP verbs
pub fn all_std_methods() -> Vec<Method> {
    vec![Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch]
}

/// Returns HTTP Headers commonly set by clients
pub fn common_req_headers() -> Vec<unicase::UniCase<String>> {
    vec![UniCase("Authorization".to_owned()),
         // To allow application/json
         UniCase("Content-Type".to_owned()),
         // Set by some js libs
         UniCase("X-Requested-With".to_owned())]
}

impl CorsMiddleware {
    /// New middleware with sensible permissive settings.
    /// Allows any origin.
    /// Allows all standard HTTP methods.
    /// Allows common request headers (as defined by `common_req_headers()`.
    /// Does not expose any headers.
    /// Does not allow credentials.
    /// Sets MaxAge to 60 minutes.
    pub fn permissive() -> CorsMiddleware {
        CorsMiddleware {
            allowed_origins: AllowedOrigins::Any { prefer_wildcard: false },
            allowed_methods: all_std_methods(),
            allowed_headers: common_req_headers(),
            exposed_headers: vec![],
            allow_credentials: false,
            max_age_seconds: 60 * 60,
        }
    }

    /// Handle a potential CORS request. Detects if this is a
    /// preflight or normal method, adding CORS headers as appropriate
    fn handle(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // http://stackoverflow.com/questions/14015118/
        // what-is-the-expected-response-to-an-invalid-cors-request
        // http://stackoverflow.com/questions/32331737/
        // how-can-i-identify-a-cors-preflight-request
        if req.method == Options && req.headers.get::<AccessControlRequestMethod>().is_some() {
            self.handle_preflight(req, handler)
        } else {
            self.handle_normal(req, handler)
        }
    }

    /// Handle a preflight request
    fn handle_preflight(&self, req: &mut Request, _: &Handler) -> IronResult<Response> {
        // Successful preflight status code is NoContent
        let mut res = Response::with((status::NoContent));

        // - Preflight request
        // - 1.If the Origin header is not present terminate this set of steps. The request is
        // - outside the scope of this specification.
        let maybe_origin = req.headers.get::<OriginHeader>();
        if maybe_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       "Preflight request without Origin header"));
            return Ok(resp);
        }
        let origin = maybe_origin.unwrap();
        //
        // - 2.If the value of the Origin header is not a case-sensitive match for any of the
        // - values in list of origins do not set any additional headers and terminate this
        // - set of steps.
        //
        // - Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        // - Note: The Origin header can only contain a single origin as the user agent
        //       will not follow redirects.
        //
        let origin_str = origin.to_string();
        let allowed_origin = self.allowed_origins.allowed_for(&origin_str, self.allow_credentials);
        if allowed_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       format!("Preflight request requesting \
                                       disallowed origin '{}'",
                                               origin_str)));
            return Ok(resp);
        }
        //
        // - 3. Let method be the value as result of parsing the Access-Control-Request-Method
        // - header.
        //
        // - If there is no Access-Control-Request-Method header or if parsing failed, do not
        // - set any additional headers and terminate this set of steps. The request is
        // - outside the scope of this specification.

        // We can assume that this header exists, since we already checked that before
        // classifying the request as preflight
        let requested_method = req.headers.get::<AccessControlRequestMethod>().unwrap();

        //
        // - 4. Let header field-names be the values as result of parsing the
        // - Access-Control-Request-Headers headers.
        //
        // - If there are no Access-Control-Request-Headers headers let header field-names be
        // - the empty list.
        //
        // - If parsing failed do not set any additional headers and terminate this set of
        // - steps. The request is outside the scope of this specification.
        //
        let empty_vec: Vec<UniCase<String>> = vec![];
        let maybe_requested_headers = req.headers.get::<AccessControlRequestHeaders>();
        let requested_headers: &Vec<UniCase<String>> = if maybe_requested_headers.is_some() {
            &maybe_requested_headers.unwrap().0
        } else {
            &empty_vec
        };
        // - 5.If method is not a case-sensitive match for any of the values in list of
        // -   methods do not set any additional headers and terminate this set of steps.
        //
        // - Always matching is acceptable since the list of methods can be unbounded.
        //
        if !self.allowed_methods.contains(requested_method) {
            return Ok(Response::with((status::BadRequest,
                                      format!("Preflight request requesting disallowed method {}",
                                              requested_method))));
        }
        // - 6. If any of the header field-names is not a ASCII case-insensitive match for any
        // - of the values in list of headers do not set any additional headers and terminate
        // - this set of steps.
        let requested_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(requested_headers.iter().cloned());
        let allowed_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(self.allowed_headers.iter().cloned());
        let disallowed_headers: HashSet<UniCase<String>> =
            requested_headers_set.difference(&allowed_headers_set).cloned().collect();
        if !disallowed_headers.is_empty() {
            let a = disallowed_headers.iter()
                .map(|uh| uh.to_string())
                .collect::<Vec<_>>()
                .join(",");
            let msg = format!("Preflight request requesting disallowed header(s) {}", a);
            return Ok(Response::with((status::BadRequest, msg)));

        }
        //
        // - Always matching is acceptable since the list of headers can be unbounded.
        //
        // - 7. If the resource supports credentials add a single Access-Control-Allow-Origin
        // - header, with the value of the Origin header as value, and add a single
        // - Access-Control-Allow-Credentials header with the case-sensitive string "true" as
        // - value.
        //
        // - Otherwise, add a single Access-Control-Allow-Origin header, with either the
        // - value of the Origin header or the string "*" as value.
        //
        // - The string "*" cannot be used for a resource that supports credentials.
        //
        if self.allow_credentials {
            res.headers.set(AccessControlAllowCredentials);
        }
        res.headers.set(AccessControlAllowOrigin::Value(allowed_origin.unwrap()));
        // - 8. Optionally add a single Access-Control-Max-Age header with as value the amount
        // - of seconds the user agent is allowed to cache the result of the request.
        res.headers.set(AccessControlMaxAge(self.max_age_seconds));
        //
        // - 9. If method is a simple method this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Methods headers consisting of (a subset of)
        // - the list of methods.
        //
        // - If a method is a simple method it does not need to be listed, but this is not
        // - prohibited.
        //
        // - Since the list of methods can be unbounded, simply returning the method
        // - indicated by Access-Control-Request-Method (if supported) can be enough.
        //
        res.headers.set(AccessControlAllowMethods(self.allowed_methods.clone()));
        // - 10.If each of the header field-names is a simple header and none is Content-Type,
        // - this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Headers headers consisting of (a subset of)
        // - the list of headers.
        //
        // - If a header field name is a simple header and is not Content-Type, it is not
        // - required to be listed. Content-Type is to be listed as only a subset of its
        // - values makes it qualify as simple header.
        //
        // - Since the list of headers can be unbounded, simply returning supported headers
        // - from Access-Control-Allow-Headers can be enough.
        res.headers.set(AccessControlAllowHeaders(self.allowed_headers.clone()));
        Ok(res)
    }

    /// Handle a normal (i.e non-preflight) CORS request
    fn handle_normal(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // Normal request
        // - 1.If the Origin header is not present terminate this set of steps. The request is
        // - outside the scope of this specification.
        let have_origin;
        {
            let maybe_origin = req.headers.get::<OriginHeader>();
            have_origin = maybe_origin.is_some();
        }
        if !have_origin {
            // No origin, treat as normal request.
            // We could return error here if we wanted according to
            // https://tools.ietf.org/id/draft-abarth-origin-03.html#rfc.section.6
            return handler.handle(req);
        }
        //
        // - 2.If the value of the Origin header is not a case-sensitive match for any of the
        // - values in list of origins, do not set any additional headers and terminate this
        // - set of steps.
        //
        // - Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        let origin = req.headers
            .get::<OriginHeader>()
            .unwrap()
            .clone();
        let origin_str = origin.to_string();
        let allowed_origin = self.allowed_origins.allowed_for(&origin_str, self.allow_credentials);
        if allowed_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       format!("Normal request requesting \
                                       disallowed origin '{}'",
                                               origin_str)));
            return Ok(resp);
        }
        let result = handler.handle(req);
        match result {
            Ok(mut res) => {
                //
                // - 3. If the resource supports credentials add a single
                // - Access-Control-Allow-Origin
                // - header, with the value of the Origin header as value, and add a single
                // - Access-Control-Allow-Credentials header with the case-sensitive string
                // - "true" as value.
                //
                // - Otherwise, add a single Access-Control-Allow-Origin header, with either the
                // - value of the Origin header or the string "*" as value.
                //
                // - Note: The string "*" cannot be used for a resource that supports credentials.
                if self.allow_credentials {
                    res.headers.set(AccessControlAllowCredentials);
                }
                res.headers.set(AccessControlAllowOrigin::Value(allowed_origin.unwrap()));
                //
                // - 4. If the list of exposed headers is not empty add one or more
                // - Access-Control-Expose-Headers headers, with as values the header field names
                // - given in the list of exposed headers.
                res.headers.set(AccessControlExposeHeaders(self.exposed_headers.clone()));
                Ok(res)
            }
            _ => result,
        }

    }

    /// Util function for wrapping the supplied handler with this CorsMiddleware.
    /// Works by constructing a chain with only this middleware linked.
    pub fn decorate<T: Handler>(self, handler: T) -> Chain {
        let mut chain = Chain::new(handler);
        chain.link_around(self);
        chain
    }
}

impl AroundMiddleware for CorsMiddleware {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(move |req: &mut Request| self.handle(req, &handler))
    }
}
<commit_msg>clippy fix<commit_after>extern crate iron;
extern crate unicase;
extern crate hyper;

use unicase::UniCase;
use iron::prelude::*;
use iron::method::Method;
use iron::method::Method::*;
use iron::status;
use iron::headers::Origin as OriginHeader;
use iron::headers::{AccessControlRequestMethod, AccessControlRequestHeaders,
                    AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlMaxAge,
                    AccessControlAllowMethods, AccessControlAllowCredentials,
                    AccessControlExposeHeaders};
use iron::middleware::{AroundMiddleware, Handler};
use std::collections::HashSet;
use std::iter::FromIterator;
pub use origin::Origin;

mod origin;

/// Specifies which Origins are allowed to access this resource
pub enum AllowedOrigins {
    /// Any Origin is allowed.
    Any {
        /// If set, wildcard ('*') will be used as value
        /// for AccessControlAllowOrigin if possible. If not set,
        /// echoing the incoming Origin will be preferred.
        /// If credentials are allowed, echoing will always be used.
        prefer_wildcard: bool,
    },
    /// Allow a specific set of origins. Allowing for null origins is
    /// not supported. Partly since the Iron cannot parse a null Origin header,
    /// but also due to it being considered bad practice:
    /// https://w3c.github.io/webappsec-cors-for-developers/
    Specific(HashSet<Origin>),
}

impl AllowedOrigins {
    /// Returns the value of AccessControlAllowOrigin
    /// given the specified Origin header in the request. The allow_credentials
    /// flag is supplied since AccessControlAllowOrigin * is forbidden when credentials
    /// are allowed.
    ///
    /// We're not using the iron Origin header to construct an Origin directly, since
    /// we are dependent on url.port_or_known_default() to get the default port. This
    /// method is only available after parsing the Origin header to an URL.
    fn allowed_for(&self, origin_string: &str, allow_credentials: bool) -> Option<String> {
        match Origin::parse(origin_string) {
            Err(_) => None,
            Ok(origin) => {
                match self {
                    &AllowedOrigins::Any { prefer_wildcard } => {
                        if allow_credentials {
                            // Allow credentials does not permit using wildcard
                            Some(origin_string.to_owned())
                        } else {
                            // Use wildcard if preferred
                            Some(if prefer_wildcard {
                                     "*".to_owned()
                                 } else {
                                     origin_string.to_owned()
                                 })
                        }
                    }
                    &AllowedOrigins::Specific(ref allowed) => {
                        if allowed.contains(&origin) {
                            Some(origin_string.to_owned())
                        } else {
                            None
                        }
                    }
                }
            }
        }

    }
}

/// An iron middleware which implements CORS
///
/// Note: Not using `Vec<Header>` to represent
/// headers since the iron `Header`
/// type is representing a `Key=Value` pair and not just the key.
/// In other words, the Header type represents an instance of
/// a HTTP header. What we need here is something representing the
/// type of header. Since the Header trait defines a a method
/// `fn header_name() -> &'static str`, we conclude that Iron uses
/// strings to represent this.
pub struct CorsMiddleware {
    /// The origins which are allowed to access this resource
    pub allowed_origins: AllowedOrigins,
    /// The methods allowed to perform on this resource
    pub allowed_methods: Vec<Method>,
    /// The headers allowed to send to this resource
    pub allowed_headers: Vec<UniCase<String>>,
    /// The headers allowed to read from the response from this resource
    pub exposed_headers: Vec<UniCase<String>>,
    /// Whether to allow clients to send cookies to this resource or not
    pub allow_credentials: bool,
    /// Defines the max cache lifetime for operations allowed on this
    /// resource
    pub max_age_seconds: u32,
}

/// Returns all standard HTTP verbs
pub fn all_std_methods() -> Vec<Method> {
    vec![Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch]
}

/// Returns HTTP Headers commonly set by clients
pub fn common_req_headers() -> Vec<unicase::UniCase<String>> {
    vec![UniCase("Authorization".to_owned()),
         // To allow application/json
         UniCase("Content-Type".to_owned()),
         // Set by some js libs
         UniCase("X-Requested-With".to_owned())]
}

impl CorsMiddleware {
    /// New middleware with sensible permissive settings.
    /// Allows any origin.
    /// Allows all standard HTTP methods.
    /// Allows common request headers (as defined by `common_req_headers()`.
    /// Does not expose any headers.
    /// Does not allow credentials.
    /// Sets MaxAge to 60 minutes.
    pub fn permissive() -> CorsMiddleware {
        CorsMiddleware {
            allowed_origins: AllowedOrigins::Any { prefer_wildcard: false },
            allowed_methods: all_std_methods(),
            allowed_headers: common_req_headers(),
            exposed_headers: vec![],
            allow_credentials: false,
            max_age_seconds: 60 * 60,
        }
    }

    /// Handle a potential CORS request. Detects if this is a
    /// preflight or normal method, adding CORS headers as appropriate
    fn handle(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // http://stackoverflow.com/questions/14015118/
        // what-is-the-expected-response-to-an-invalid-cors-request
        // http://stackoverflow.com/questions/32331737/
        // how-can-i-identify-a-cors-preflight-request
        if req.method == Options && req.headers.get::<AccessControlRequestMethod>().is_some() {
            self.handle_preflight(req, handler)
        } else {
            self.handle_normal(req, handler)
        }
    }

    /// Handle a preflight request
    fn handle_preflight(&self, req: &mut Request, _: &Handler) -> IronResult<Response> {
        // Successful preflight status code is NoContent
        let mut res = Response::with(status::NoContent);

        // - Preflight request
        // - 1.If the Origin header is not present terminate this set of steps. The request is
        // - outside the scope of this specification.
        let maybe_origin = req.headers.get::<OriginHeader>();
        if maybe_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       "Preflight request without Origin header"));
            return Ok(resp);
        }
        let origin = maybe_origin.unwrap();
        //
        // - 2.If the value of the Origin header is not a case-sensitive match for any of the
        // - values in list of origins do not set any additional headers and terminate this
        // - set of steps.
        //
        // - Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        // - Note: The Origin header can only contain a single origin as the user agent
        //       will not follow redirects.
        //
        let origin_str = origin.to_string();
        let allowed_origin = self.allowed_origins.allowed_for(&origin_str, self.allow_credentials);
        if allowed_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       format!("Preflight request requesting \
                                       disallowed origin '{}'",
                                               origin_str)));
            return Ok(resp);
        }
        //
        // - 3. Let method be the value as result of parsing the Access-Control-Request-Method
        // - header.
        //
        // - If there is no Access-Control-Request-Method header or if parsing failed, do not
        // - set any additional headers and terminate this set of steps. The request is
        // - outside the scope of this specification.

        // We can assume that this header exists, since we already checked that before
        // classifying the request as preflight
        let requested_method = req.headers.get::<AccessControlRequestMethod>().unwrap();

        //
        // - 4. Let header field-names be the values as result of parsing the
        // - Access-Control-Request-Headers headers.
        //
        // - If there are no Access-Control-Request-Headers headers let header field-names be
        // - the empty list.
        //
        // - If parsing failed do not set any additional headers and terminate this set of
        // - steps. The request is outside the scope of this specification.
        //
        let empty_vec: Vec<UniCase<String>> = vec![];
        let maybe_requested_headers = req.headers.get::<AccessControlRequestHeaders>();
        let requested_headers: &Vec<UniCase<String>> = if maybe_requested_headers.is_some() {
            &maybe_requested_headers.unwrap().0
        } else {
            &empty_vec
        };
        // - 5.If method is not a case-sensitive match for any of the values in list of
        // -   methods do not set any additional headers and terminate this set of steps.
        //
        // - Always matching is acceptable since the list of methods can be unbounded.
        //
        if !self.allowed_methods.contains(requested_method) {
            return Ok(Response::with((status::BadRequest,
                                      format!("Preflight request requesting disallowed method {}",
                                              requested_method))));
        }
        // - 6. If any of the header field-names is not a ASCII case-insensitive match for any
        // - of the values in list of headers do not set any additional headers and terminate
        // - this set of steps.
        let requested_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(requested_headers.iter().cloned());
        let allowed_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(self.allowed_headers.iter().cloned());
        let disallowed_headers: HashSet<UniCase<String>> =
            requested_headers_set.difference(&allowed_headers_set).cloned().collect();
        if !disallowed_headers.is_empty() {
            let a = disallowed_headers.iter()
                .map(|uh| uh.to_string())
                .collect::<Vec<_>>()
                .join(",");
            let msg = format!("Preflight request requesting disallowed header(s) {}", a);
            return Ok(Response::with((status::BadRequest, msg)));

        }
        //
        // - Always matching is acceptable since the list of headers can be unbounded.
        //
        // - 7. If the resource supports credentials add a single Access-Control-Allow-Origin
        // - header, with the value of the Origin header as value, and add a single
        // - Access-Control-Allow-Credentials header with the case-sensitive string "true" as
        // - value.
        //
        // - Otherwise, add a single Access-Control-Allow-Origin header, with either the
        // - value of the Origin header or the string "*" as value.
        //
        // - The string "*" cannot be used for a resource that supports credentials.
        //
        if self.allow_credentials {
            res.headers.set(AccessControlAllowCredentials);
        }
        res.headers.set(AccessControlAllowOrigin::Value(allowed_origin.unwrap()));
        // - 8. Optionally add a single Access-Control-Max-Age header with as value the amount
        // - of seconds the user agent is allowed to cache the result of the request.
        res.headers.set(AccessControlMaxAge(self.max_age_seconds));
        //
        // - 9. If method is a simple method this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Methods headers consisting of (a subset of)
        // - the list of methods.
        //
        // - If a method is a simple method it does not need to be listed, but this is not
        // - prohibited.
        //
        // - Since the list of methods can be unbounded, simply returning the method
        // - indicated by Access-Control-Request-Method (if supported) can be enough.
        //
        res.headers.set(AccessControlAllowMethods(self.allowed_methods.clone()));
        // - 10.If each of the header field-names is a simple header and none is Content-Type,
        // - this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Headers headers consisting of (a subset of)
        // - the list of headers.
        //
        // - If a header field name is a simple header and is not Content-Type, it is not
        // - required to be listed. Content-Type is to be listed as only a subset of its
        // - values makes it qualify as simple header.
        //
        // - Since the list of headers can be unbounded, simply returning supported headers
        // - from Access-Control-Allow-Headers can be enough.
        res.headers.set(AccessControlAllowHeaders(self.allowed_headers.clone()));
        Ok(res)
    }

    /// Handle a normal (i.e non-preflight) CORS request
    fn handle_normal(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // Normal request
        // - 1.If the Origin header is not present terminate this set of steps. The request is
        // - outside the scope of this specification.
        let have_origin;
        {
            let maybe_origin = req.headers.get::<OriginHeader>();
            have_origin = maybe_origin.is_some();
        }
        if !have_origin {
            // No origin, treat as normal request.
            // We could return error here if we wanted according to
            // https://tools.ietf.org/id/draft-abarth-origin-03.html#rfc.section.6
            return handler.handle(req);
        }
        //
        // - 2.If the value of the Origin header is not a case-sensitive match for any of the
        // - values in list of origins, do not set any additional headers and terminate this
        // - set of steps.
        //
        // - Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        let origin = req.headers
            .get::<OriginHeader>()
            .unwrap()
            .clone();
        let origin_str = origin.to_string();
        let allowed_origin = self.allowed_origins.allowed_for(&origin_str, self.allow_credentials);
        if allowed_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       format!("Normal request requesting \
                                       disallowed origin '{}'",
                                               origin_str)));
            return Ok(resp);
        }
        let result = handler.handle(req);
        match result {
            Ok(mut res) => {
                //
                // - 3. If the resource supports credentials add a single
                // - Access-Control-Allow-Origin
                // - header, with the value of the Origin header as value, and add a single
                // - Access-Control-Allow-Credentials header with the case-sensitive string
                // - "true" as value.
                //
                // - Otherwise, add a single Access-Control-Allow-Origin header, with either the
                // - value of the Origin header or the string "*" as value.
                //
                // - Note: The string "*" cannot be used for a resource that supports credentials.
                if self.allow_credentials {
                    res.headers.set(AccessControlAllowCredentials);
                }
                res.headers.set(AccessControlAllowOrigin::Value(allowed_origin.unwrap()));
                //
                // - 4. If the list of exposed headers is not empty add one or more
                // - Access-Control-Expose-Headers headers, with as values the header field names
                // - given in the list of exposed headers.
                res.headers.set(AccessControlExposeHeaders(self.exposed_headers.clone()));
                Ok(res)
            }
            _ => result,
        }

    }

    /// Util function for wrapping the supplied handler with this CorsMiddleware.
    /// Works by constructing a chain with only this middleware linked.
    pub fn decorate<T: Handler>(self, handler: T) -> Chain {
        let mut chain = Chain::new(handler);
        chain.link_around(self);
        chain
    }
}

impl AroundMiddleware for CorsMiddleware {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(move |req: &mut Request| self.handle(req, &handler))
    }
}
<|endoftext|>


<commit_before>//! # generator
//!
//! Rust generator library
//!

#![cfg_attr(nightly, feature(core_intrinsics))]
#![cfg_attr(nightly, feature(thread_local))]
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]
#![allow(deprecated)]

#[macro_use]
extern crate log;

mod detail;
mod gen_impl;
mod reg_context;
mod rt;
mod scope;
mod stack;
mod yield_;

pub use crate::gen_impl::{Generator, Gn};
pub use crate::rt::{get_local_data, is_generator, Error};
pub use crate::scope::Scope;
pub use crate::yield_::{
    co_get_yield, co_set_para, co_yield_with, done, get_yield, yield_, yield_from, yield_with,
};
<commit_msg>:pencil: fix 2021 edition panic warning<commit_after>//! # generator
//!
//! Rust generator library
//!

#![cfg_attr(nightly, feature(core_intrinsics))]
#![cfg_attr(nightly, feature(thread_local))]
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]
#![allow(deprecated)]
#![allow(non_fmt_panic)]

#[macro_use]
extern crate log;

mod detail;
mod gen_impl;
mod reg_context;
mod rt;
mod scope;
mod stack;
mod yield_;

pub use crate::gen_impl::{Generator, Gn};
pub use crate::rt::{get_local_data, is_generator, Error};
pub use crate::scope::Scope;
pub use crate::yield_::{
    co_get_yield, co_set_para, co_yield_with, done, get_yield, yield_, yield_from, yield_with,
};
<|endoftext|>


<commit_before>use std::error::FromError;
use std::io::{BufferedStream, IoError};
use std::io::net::tcp::TcpStream;

#[derive(Show)]
pub enum MemcacheError {
    InternalIoError(IoError),
    ServerError
}

impl FromError<IoError> for MemcacheError {
    fn from_error(err: IoError) -> MemcacheError {
        MemcacheError::InternalIoError(err)
    }
}

pub type MemcacheResult<T> = Result<T, MemcacheError>;

pub struct Connection {
    pub host: String,
    pub port: u16,
    stream: BufferedStream<TcpStream>,
}

impl Connection {
    pub fn flush(&mut self) -> MemcacheResult<()> {
        try!{ self.stream.write_str("flush_all\r\n") };
        try!{ self.stream.flush() };
        let result = try!{ self.stream.read_line() };
        if result.as_slice() != "OK\r\n" {
            return Err(MemcacheError::ServerError);
        }
        return Ok(());
    }

    pub fn delete(&mut self, key: &str) -> MemcacheResult<bool> {
        try!{ self.stream.write_str(format!("delete {}\r\n", key).as_slice()) };
        try!{ self.stream.flush() };
        let result = try! { self.stream.read_line() };
        if result.as_slice() == "DELETED\r\n" {
            return Ok(true);
        } else if result.as_slice() == "NOT_FOUND\r\n" {
            return Ok(false);
        } else {
            return Err(MemcacheError::ServerError);
        }
    }

    pub fn get(&mut self, key: &str) -> MemcacheResult<Option<(Vec<u8>, u16)>> {
        try!{ self.stream.write_str(format!("get {}\r\n", key).as_slice()) };
        try!{ self.stream.flush() };
        let result = try!{ self.stream.read_line() };
        if result.as_slice() == "END\r\n" {
            return Ok(None);
        }
        let header: Vec<&str> = result.split(' ').collect();
        if header.len() != 4 || header[0] != "VALUE" || header[1] != key {
            return Err(MemcacheError::ServerError);
        }
        let flags: u16 = match header[2].trim().parse() {
            Some(flags) => { flags }
            None => { return Err(MemcacheError::ServerError); }
        };
        let length: usize = match header[3].trim().parse() {
            Some(length) => { length }
            None => { return Err(MemcacheError::ServerError); }
        };
        let value = try!{ self.stream.read_exact(length) };
        return Ok(Some((value, flags)));
    }

    pub fn set(&mut self, key: &str, value: &[u8], exptime: isize, flags: u16) -> MemcacheResult<bool> {
        try!{ self.stream.write_str(format!("set {} {} {} {}\r\n", key, flags, exptime, value.len()).as_slice()) };
        try!{ self.stream.write(value) };
        try!{ self.stream.write_str("\r\n") };
        try!{ self.stream.flush() };
        let result = try!{ self.stream.read_line() };
        if result.as_slice() == "STORED\r\n" {
            return Ok(true);
        } else if result.as_slice() == "NOT_STORED\r\n" {
            return Ok(false);
        }
        return Err(MemcacheError::ServerError);
    }

    pub fn incr(&mut self, key: &str, value: u64) -> MemcacheResult<Option<(isize)>> {
        try!{ self.stream.write_str(format!("incr {} {:b}\r\n", key, value).as_slice()) };
        try!{ self.stream.flush() };
        let result = try!{ self.stream.read_line() };
        if result.as_slice() == "NOT_FOUND\r\n" {
            return Ok(None);
        }
        let x: &[_] = &['\r', '\n'];
        // let trimed_result = result.trim_right_matches(x);
        let value: isize = match result.trim_right_matches(x).parse() {
            Some(value) => { value }
            None => { return Err(MemcacheError::ServerError) }
        };
        return Ok(Some(value));
    }

    pub fn decr(&mut self, key: &str, value: u64) -> MemcacheResult<Option<(isize)>> {
        try!{ self.stream.write_str(format!("decr {} {:b}\r\n", key, value).as_slice()) };
        try!{ self.stream.flush() };
        let result = try!{ self.stream.read_line() };
        if result.as_slice() == "NOT_FOUND\r\n" {
            return Ok(None);
        }
        let x: &[_] = &['\r', '\n'];
        // let trimed_result = result.trim_right_matches(x);
        let value: isize = match result.trim_right_matches(x).parse() {
            Some(value) => { value }
            None => { return Err(MemcacheError::ServerError) }
        };
        return Ok(Some(value));
    }

    pub fn connect(host: &str, port: u16) -> MemcacheResult<Connection> {
        let stream = try!{ TcpStream::connect((host, port)) };
        return Ok(Connection{
            host: host.to_string(),
            port: port,
            stream: BufferedStream::new(stream)
        });
    }
}

#[test]
fn test_connect() -> () {
    Connection::connect("localhost", 2333).unwrap();
}

#[test]
fn test_flush() -> () {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
}

#[test]
fn test_set() -> () {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
    assert!{ conn.set("foo", b"bar", 10, 0).unwrap() == true };
}

#[test]
fn test_get() -> () {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
    assert!{ conn.get("foo").unwrap() == None };

    assert!{ conn.set("foo", b"bar", 0, 10).unwrap() == true };
    let result = conn.get("foo").unwrap().unwrap();
    assert!{ result.0 == b"bar" };
    assert!{ result.1 == 10 };
}

#[test]
fn test_delete() -> () {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
    assert!{ conn.delete("foo").unwrap() == false };
}

#[test]
fn test_incr() {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
    let mut result = conn.incr("lie", 42);
    assert!{ result.unwrap() == None };

    conn.flush().unwrap();
    conn.set("truth", format!("{}", 42).as_bytes(), 0, 0).unwrap();
    result = conn.incr("truth", 1);
    assert!{ result.unwrap().unwrap() == 43 };
}

#[test]
fn test_decr() {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
    let mut result = conn.decr("lie", 42);
    assert!{ result.unwrap() == None };

    conn.flush().unwrap();
    conn.set("truth", format!("{}", 42).as_bytes(), 0, 0).unwrap();
    result = conn.decr("truth", 1);
    assert!{ result.unwrap().unwrap() == 41 };
}
<commit_msg>makes nightly happy<commit_after>use std::error::FromError;
use std::io::{BufferedStream, IoError};
use std::io::net::tcp::TcpStream;

#[derive(Show)]
pub enum MemcacheError {
    InternalIoError(IoError),
    ServerError
}

impl FromError<IoError> for MemcacheError {
    fn from_error(err: IoError) -> MemcacheError {
        MemcacheError::InternalIoError(err)
    }
}

pub type MemcacheResult<T> = Result<T, MemcacheError>;

pub struct Connection {
    pub host: String,
    pub port: u16,
    stream: BufferedStream<TcpStream>,
}

impl Connection {
    pub fn flush(&mut self) -> MemcacheResult<()> {
        try!{ self.stream.write_str("flush_all\r\n") };
        try!{ self.stream.flush() };
        let result = try!{ self.stream.read_line() };
        if result.as_slice() != "OK\r\n" {
            return Err(MemcacheError::ServerError);
        }
        return Ok(());
    }

    pub fn delete(&mut self, key: &str) -> MemcacheResult<bool> {
        try!{ self.stream.write_str(format!("delete {}\r\n", key).as_slice()) };
        try!{ self.stream.flush() };
        let result = try! { self.stream.read_line() };
        if result.as_slice() == "DELETED\r\n" {
            return Ok(true);
        } else if result.as_slice() == "NOT_FOUND\r\n" {
            return Ok(false);
        } else {
            return Err(MemcacheError::ServerError);
        }
    }

    pub fn get(&mut self, key: &str) -> MemcacheResult<Option<(Vec<u8>, u16)>> {
        try!{ self.stream.write_str(format!("get {}\r\n", key).as_slice()) };
        try!{ self.stream.flush() };
        let result = try!{ self.stream.read_line() };
        if result.as_slice() == "END\r\n" {
            return Ok(None);
        }
        let header: Vec<&str> = result.split(' ').collect();
        if header.len() != 4 || header[0] != "VALUE" || header[1] != key {
            return Err(MemcacheError::ServerError);
        }
        let flags: u16 = match header[2].trim().parse() {
            Some(flags) => { flags }
            None => { return Err(MemcacheError::ServerError); }
        };
        let length: usize = match header[3].trim().parse() {
            Some(length) => { length }
            None => { return Err(MemcacheError::ServerError); }
        };
        let value = try!{ self.stream.read_exact(length) };
        return Ok(Some((value, flags)));
    }

    pub fn set(&mut self, key: &str, value: &[u8], exptime: isize, flags: u16) -> MemcacheResult<bool> {
        try!{ self.stream.write_str(format!("set {} {} {} {}\r\n", key, flags, exptime, value.len()).as_slice()) };
        try!{ self.stream.write(value) };
        try!{ self.stream.write_str("\r\n") };
        try!{ self.stream.flush() };
        let result = try!{ self.stream.read_line() };
        if result.as_slice() == "STORED\r\n" {
            return Ok(true);
        } else if result.as_slice() == "NOT_STORED\r\n" {
            return Ok(false);
        }
        return Err(MemcacheError::ServerError);
    }

    pub fn incr(&mut self, key: &str, value: u64) -> MemcacheResult<Option<(isize)>> {
        try!{ self.stream.write_str(format!("incr {} {:b}\r\n", key, value).as_slice()) };
        try!{ self.stream.flush() };
        let result = try!{ self.stream.read_line() };
        if result.as_slice() == "NOT_FOUND\r\n" {
            return Ok(None);
        }
        let x: &[_] = &['\r', '\n'];
        // let trimed_result = result.trim_right_matches(x);
        let value: isize = match result.trim_right_matches(x).parse() {
            Some(value) => { value }
            None => { return Err(MemcacheError::ServerError) }
        };
        return Ok(Some(value));
    }

    pub fn decr(&mut self, key: &str, value: u64) -> MemcacheResult<Option<(isize)>> {
        try!{ self.stream.write_str(format!("decr {} {:b}\r\n", key, value).as_slice()) };
        try!{ self.stream.flush() };
        let result = try!{ self.stream.read_line() };
        if result.as_slice() == "NOT_FOUND\r\n" {
            return Ok(None);
        }
        let x: &[_] = &['\r', '\n'];
        // let trimed_result = result.trim_right_matches(x);
        let value: isize = match result.trim_right_matches(x).parse() {
            Some(value) => { value }
            None => { return Err(MemcacheError::ServerError) }
        };
        return Ok(Some(value));
    }

    pub fn connect(host: &str, port: u16) -> MemcacheResult<Connection> {
        let stream = try!{ TcpStream::connect((host, port)) };
        return Ok(Connection{
            host: host.to_string(),
            port: port,
            stream: BufferedStream::new(stream)
        });
    }
}

#[test]
fn test_connect() {
    Connection::connect("localhost", 2333).unwrap();
}

#[test]
fn test_flush() {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
}

#[test]
fn test_set() {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
    assert!{ conn.set("foo", b"bar", 10, 0).unwrap() == true };
}

#[test]
fn test_get() {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
    assert!{ conn.get("foo").unwrap() == None };

    assert!{ conn.set("foo", b"bar", 0, 10).unwrap() == true };
    let result = conn.get("foo").unwrap().unwrap();
    assert!{ result.0 == b"bar" };
    assert!{ result.1 == 10 };
}

#[test]
fn test_delete() {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
    assert!{ conn.delete("foo").unwrap() == false };
}

#[test]
fn test_incr() {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
    let mut result = conn.incr("lie", 42);
    assert!{ result.unwrap() == None };

    conn.flush().unwrap();
    conn.set("truth", b"42", 0, 0).unwrap();
    result = conn.incr("truth", 1);
    assert!{ result.unwrap().unwrap() == 43 };
}

#[test]
fn test_decr() {
    let mut conn = Connection::connect("localhost", 2333).unwrap();
    conn.flush().unwrap();
    let mut result = conn.decr("lie", 42);
    assert!{ result.unwrap() == None };

    conn.flush().unwrap();
    conn.set("truth", b"42", 0, 0).unwrap();
    result = conn.decr("truth", 1);
    assert!{ result.unwrap().unwrap() == 41 };
}
<|endoftext|>


<commit_before>#![cfg_attr(all(feature = "bench", test), feature(test))]

extern crate num;

mod butterflies;

use num::{Complex, Zero, One, Float, Num, FromPrimitive, Signed};
use num::traits::cast;
use std::f32;

use butterflies::{butterfly_2, butterfly_3, butterfly_4, butterfly_5};

enum Algorithm<T> {
    MixedRadix(Vec<(usize, usize)>, Vec<Complex<T>>),
    Radix4,
    Noop,
}

pub struct FFT<T> {
    algorithm: Algorithm<T>,
    twiddles: Vec<Complex<T>>,
    inverse: bool,
}

impl<T> FFT<T> where T: Signed + FromPrimitive + Copy {
    /// Creates a new FFT context that will process signal of length
    /// `len`. If `inverse` is `true`, then this struct will run inverse
    /// FFTs. This implementation of the FFT doesn't do any scaling on both
    /// the forward and backward transforms, so doing a forward then backward
    /// FFT on a signal will scale the signal by its length.
    pub fn new(len: usize, inverse: bool) -> Self {
        let dir = if inverse { 1 } else { -1 };

        let algorithm = if len < 2 {
            Algorithm::Noop
        } else if is_power_of_two(len) {
            Algorithm::Radix4
        } else {
            let factors = factor(len);
            let max_fft_len = factors.iter().map(|&(a, _)| a).max();
            let scratch = match max_fft_len {
                None | Some(0...5) => vec![Zero::zero(); 0],
                Some(l) => vec![Zero::zero(); l],
            };

            Algorithm::MixedRadix(factors, scratch)
        };

        FFT {
            algorithm: algorithm,
            twiddles: (0..len)
                      .map(|i| dir as f32 * i as f32 * 2.0 * f32::consts::PI / len as f32)
                      .map(|phase| Complex::from_polar(&1.0, &phase))
                      .map(|c| Complex {re: FromPrimitive::from_f32(c.re).unwrap(),
                                        im: FromPrimitive::from_f32(c.im).unwrap()})
                      .collect(),
            inverse: inverse,
        }
    }

    /// Runs the FFT on the input `signal` buffer, and places the output in the
    /// `spectrum` buffer.
    ///
    /// # Panics
    /// This method will panic if `signal` and `spectrum` are not the length
    /// specified in the struct's constructor.
    pub fn process(&mut self, signal: &[Complex<T>], spectrum: &mut [Complex<T>]) {
        assert!(signal.len() == spectrum.len());
        assert!(signal.len() == self.twiddles.len());

        match self.algorithm {
            Algorithm::Radix4 => radix_4(signal.len(), signal, spectrum, 1, &self.twiddles[..], self.inverse),
            Algorithm::MixedRadix(ref factors, ref mut scratch) =>
                cooley_tukey(signal, spectrum, 1, &self.twiddles[..], factors, scratch, self.inverse),
            Algorithm::Noop => copy_data(signal, spectrum, 1),
        }
    }
}

fn cooley_tukey<T>(signal: &[Complex<T>],
                   spectrum: &mut [Complex<T>],
                   stride: usize,
                   twiddles: &[Complex<T>],
                   factors: &[(usize, usize)],
                   scratch: &mut [Complex<T>],
                   inverse: bool) where T: Signed + FromPrimitive + Copy {
    if let Some(&(n1, n2)) = factors.first() {
        if n2 == 1 {
            // we theoretically need to compute n1 ffts of size n2
            // but n2 is 1, and a fft of size 1 is just a copy
            copy_data(signal, spectrum, stride);
        } else {
            // Recursive call to perform n1 ffts of length n2
            for i in 0..n1 {
                cooley_tukey(&signal[i * stride..],
                             &mut spectrum[i * n2..],
                             stride * n1, twiddles, &factors[1..],
                             scratch, inverse);
            }
        }

        match n1 {
            5 => unsafe { butterfly_5(spectrum, stride, twiddles, n2) },
            4 => unsafe { butterfly_4(spectrum, stride, twiddles, n2, inverse) },
            3 => unsafe { butterfly_3(spectrum, stride, twiddles, n2) },
            2 => unsafe { butterfly_2(spectrum, stride, twiddles, n2) },
            _ => butterfly(spectrum, stride, twiddles, n2, n1, &mut scratch[..n1]),
        }
    }
}

fn radix_4<T>(  size: usize,
                signal: &[Complex<T>],
                spectrum: &mut [Complex<T>],
                stride: usize,
                twiddles: &[Complex<T>],
                inverse: bool) where T: Signed + FromPrimitive + Copy {
    match size {
        4 => unsafe {
            copy_data_4(signal, spectrum, stride);
            butterfly_4(spectrum, stride, twiddles, 1, inverse)
        },
        2 => unsafe {
            copy_data_2(signal, spectrum, stride);
            butterfly_2(spectrum, stride, twiddles, 1)
        },
        _ => {
            for i in 0..4 {
                radix_4(
                    size / 4,
                    &signal[i * stride..],
                    &mut spectrum[i * (size / 4)..],
                    stride * 4, twiddles, inverse
                    );
            }
            unsafe { butterfly_4(spectrum, stride, twiddles, size/4, inverse) };
        }
    }
}

fn butterfly<T: Num + Copy>(data: &mut [Complex<T>], stride: usize,
                            twiddles: &[Complex<T>], num_ffts: usize,
                            fft_len: usize, scratch: &mut [Complex<T>]) {
    // for each fft we have to perform...
    for fft_idx in 0..num_ffts {

        // copy over data into scratch space
        let mut data_idx = fft_idx;
        for s in scratch.iter_mut() {
            *s = unsafe { *data.get_unchecked(data_idx) };
            data_idx += num_ffts;
        }

        // perfom the butterfly from the scratch space into the original buffer
        let mut data_idx = fft_idx;
        while data_idx < fft_len * num_ffts {
            let out_sample = unsafe { data.get_unchecked_mut(data_idx) };
            *out_sample = Zero::zero();
            let mut twiddle_idx = 0usize;
            for in_sample in scratch.iter() {
                let twiddle = unsafe { twiddles.get_unchecked(twiddle_idx) };
                *out_sample = *out_sample + in_sample * twiddle;
                twiddle_idx += stride * data_idx;
                if twiddle_idx >= twiddles.len() { twiddle_idx -= twiddles.len() }
            }
            data_idx += num_ffts;
        }

    }
}

fn copy_data<T>(signal: &[Complex<T>],
                spectrum: &mut [Complex<T>],
                stride: usize) where T: Copy  {
    let mut spectrum_idx = 0usize;
    let mut signal_idx = 0usize;
    while signal_idx < signal.len() {
        unsafe { *spectrum.get_unchecked_mut(spectrum_idx) =
            *signal.get_unchecked(signal_idx); }
        spectrum_idx += 1;
        signal_idx += stride;
    }
}

fn copy_data_2<T>(signal: &[Complex<T>],
                spectrum: &mut [Complex<T>],
                stride: usize) where T: Copy  {
    unsafe {
        *spectrum.get_unchecked_mut(0) = *signal.get_unchecked(0);
        *spectrum.get_unchecked_mut(1) = *signal.get_unchecked(stride);
    }
}
fn copy_data_4<T>(signal: &[Complex<T>],
                spectrum: &mut [Complex<T>],
                stride: usize) where T: Signed + FromPrimitive + Copy  {
    unsafe {
        for i in 0..4 {
            *spectrum.get_unchecked_mut(i) = *signal.get_unchecked(i*stride);
        }
    }
}

pub fn dft<T: Float>(signal: &[Complex<T>], spectrum: &mut [Complex<T>]) {
    for (k, spec_bin) in spectrum.iter_mut().enumerate() {
        let mut sum = Zero::zero();
        for (i, &x) in signal.iter().enumerate() {
            let angle = cast::<_, T>(-1 * (i * k) as isize).unwrap()
                * cast(2.0 * f32::consts::PI).unwrap()
                / cast(signal.len()).unwrap();
            let twiddle = Complex::from_polar(&One::one(), &angle);
            sum = sum + twiddle * x;
        }
        *spec_bin = sum;
    }
}

/// Factors an integer into its prime factors.
fn factor(n: usize) -> Vec<(usize, usize)> {
    let mut factors = Vec::new();
    let mut next = n;
    while next > 1 {
        for div in 2..next + 1 {
            if next % div == 0 {
                next = next / div;
                factors.push((div, next));
                break;
            }
        }
    }
    return factors;
}

//returns true if n is a power of 2, false otherwise
fn is_power_of_two(n: usize) -> bool {
    return n & n - 1 == 0;
}
<commit_msg>Converted radix4 into an in-place algorithm<commit_after>#![cfg_attr(all(feature = "bench", test), feature(test))]

extern crate num;

mod butterflies;

use num::{Complex, Zero, One, Float, Num, FromPrimitive, Signed};
use num::traits::cast;
use std::f32;

use butterflies::{butterfly_2, butterfly_3, butterfly_4, butterfly_5};

enum Algorithm<T> {
    MixedRadix(Vec<(usize, usize)>, Vec<Complex<T>>),
    Radix4,
    Noop,
}

pub struct FFT<T> {
    algorithm: Algorithm<T>,
    twiddles: Vec<Complex<T>>,
    inverse: bool,
}

impl<T> FFT<T> where T: Signed + FromPrimitive + Copy {
    /// Creates a new FFT context that will process signal of length
    /// `len`. If `inverse` is `true`, then this struct will run inverse
    /// FFTs. This implementation of the FFT doesn't do any scaling on both
    /// the forward and backward transforms, so doing a forward then backward
    /// FFT on a signal will scale the signal by its length.
    pub fn new(len: usize, inverse: bool) -> Self {
        let dir = if inverse { 1 } else { -1 };

        let algorithm = if len < 2 {
            Algorithm::Noop
        } else if is_power_of_two(len) {
            Algorithm::Radix4
        } else {
            let factors = factor(len);
            let max_fft_len = factors.iter().map(|&(a, _)| a).max();
            let scratch = match max_fft_len {
                None | Some(0...5) => vec![Zero::zero(); 0],
                Some(l) => vec![Zero::zero(); l],
            };

            Algorithm::MixedRadix(factors, scratch)
        };

        FFT {
            algorithm: algorithm,
            twiddles: (0..len)
                .map(|i| dir as f32 * i as f32 * 2.0 * f32::consts::PI / len as f32)
                .map(|phase| Complex::from_polar(&1.0, &phase))
                .map(|c| {
                    Complex {
                        re: FromPrimitive::from_f32(c.re).unwrap(),
                        im: FromPrimitive::from_f32(c.im).unwrap(),
                    }
                })
                .collect(),
            inverse: inverse,
        }
    }

    /// Runs the FFT on the input `signal` buffer, and places the output in the
    /// `spectrum` buffer.
    ///
    /// # Panics
    /// This method will panic if `signal` and `spectrum` are not the length
    /// specified in the struct's constructor.
    pub fn process(&mut self, signal: &[Complex<T>], spectrum: &mut [Complex<T>]) {
        assert!(signal.len() == spectrum.len());
        assert!(signal.len() == self.twiddles.len());

        match self.algorithm {
            Algorithm::Radix4 => {
                copy_data_for_radix4(signal.len(), signal, spectrum, 1, 0, 0);
                radix_4(signal.len(),
                        spectrum,
                        1,
                        &self.twiddles[..],
                        self.inverse);
            }
            Algorithm::MixedRadix(ref factors, ref mut scratch) => {
                cooley_tukey(signal,
                             spectrum,
                             1,
                             &self.twiddles[..],
                             factors,
                             scratch,
                             self.inverse)
            }
            Algorithm::Noop => copy_data(signal, spectrum, 1),
        }
    }
}

fn cooley_tukey<T>(signal: &[Complex<T>],
                   spectrum: &mut [Complex<T>],
                   stride: usize,
                   twiddles: &[Complex<T>],
                   factors: &[(usize, usize)],
                   scratch: &mut [Complex<T>],
                   inverse: bool) where T: Signed + FromPrimitive + Copy {
    if let Some(&(n1, n2)) = factors.first() {
        if n2 == 1 {
            // we theoretically need to compute n1 ffts of size n2
            // but n2 is 1, and a fft of size 1 is just a copy
            copy_data(signal, spectrum, stride);
        } else {
            // Recursive call to perform n1 ffts of length n2
            for i in 0..n1 {
                cooley_tukey(&signal[i * stride..],
                             &mut spectrum[i * n2..],
                             stride * n1, twiddles, &factors[1..],
                             scratch, inverse);
            }
        }

        match n1 {
            5 => unsafe { butterfly_5(spectrum, stride, twiddles, n2) },
            4 => unsafe { butterfly_4(spectrum, stride, twiddles, n2, inverse) },
            3 => unsafe { butterfly_3(spectrum, stride, twiddles, n2) },
            2 => unsafe { butterfly_2(spectrum, stride, twiddles, n2) },
            _ => butterfly(spectrum, stride, twiddles, n2, n1, &mut scratch[..n1]),
        }
    }
}

fn radix_4<T>(size: usize,
              spectrum: &mut [Complex<T>],
              stride: usize,
              twiddles: &[Complex<T>],
              inverse: bool) where T: Signed + FromPrimitive + Copy {
    match size {
        4 => unsafe { butterfly_4(spectrum, stride, twiddles, 1, inverse) },
        2 => unsafe { butterfly_2(spectrum, stride, twiddles, 1) },
        _ => {
            for i in 0..4 {
                radix_4(size / 4,
                        &mut spectrum[i * (size / 4)..],
                        stride * 4,
                        twiddles,
                        inverse);
            }
            unsafe { butterfly_4(spectrum, stride, twiddles, size / 4, inverse) };
        }
    }
}

fn butterfly<T: Num + Copy>(data: &mut [Complex<T>],
                            stride: usize,
                            twiddles: &[Complex<T>],
                            num_ffts: usize,
                            fft_len: usize,
                            scratch: &mut [Complex<T>]) {
    // for each fft we have to perform...
    for fft_idx in 0..num_ffts {

        // copy over data into scratch space
        let mut data_idx = fft_idx;
        for s in scratch.iter_mut() {
            *s = unsafe { *data.get_unchecked(data_idx) };
            data_idx += num_ffts;
        }

        // perfom the butterfly from the scratch space into the original buffer
        let mut data_idx = fft_idx;
        while data_idx < fft_len * num_ffts {
            let out_sample = unsafe { data.get_unchecked_mut(data_idx) };
            *out_sample = Zero::zero();
            let mut twiddle_idx = 0usize;
            for in_sample in scratch.iter() {
                let twiddle = unsafe { twiddles.get_unchecked(twiddle_idx) };
                *out_sample = *out_sample + in_sample * twiddle;
                twiddle_idx += stride * data_idx;
                if twiddle_idx >= twiddles.len() { twiddle_idx -= twiddles.len() }
            }
            data_idx += num_ffts;
        }

    }
}

fn copy_data<T: Copy>(signal: &[Complex<T>], spectrum: &mut [Complex<T>], stride: usize)
{
    let mut spectrum_idx = 0usize;
    let mut signal_idx = 0usize;
    while signal_idx < signal.len() {
        unsafe {
            *spectrum.get_unchecked_mut(spectrum_idx) = *signal.get_unchecked(signal_idx);
        }
        spectrum_idx += 1;
        signal_idx += stride;
    }
}

// TODO: we should be able to do this in a simple loop, rather than recursively, using bit reversal
// the algorithm will be a little more complicated though due
// to us potentially using radix 2 for one of the teps
fn copy_data_for_radix4<T: Copy>(size: usize,
                           signal: &[Complex<T>],
                           spectrum: &mut [Complex<T>],
                           stride: usize,
                           signal_offset: usize,
                           spectrum_offset: usize)
{
    match size {
        4 => unsafe {
            for i in 0..4 {
                *spectrum.get_unchecked_mut(spectrum_offset + i) =
                    *signal.get_unchecked(signal_offset + i * stride);
            }
        },
        2 => unsafe {
            for i in 0..2 {
                *spectrum.get_unchecked_mut(spectrum_offset + i) =
                    *signal.get_unchecked(signal_offset + i * stride);
            }
        },
        _ => {
            for i in 0..4 {
                copy_data_for_radix4(size / 4,
                                     signal,
                                     spectrum,
                                     stride * 4,
                                     signal_offset + i * stride,
                                     spectrum_offset + i * (size / 4));
            }
        }
    }
}

pub fn dft<T: Float>(signal: &[Complex<T>], spectrum: &mut [Complex<T>]) {
    for (k, spec_bin) in spectrum.iter_mut().enumerate() {
        let mut sum = Zero::zero();
        for (i, &x) in signal.iter().enumerate() {
            let angle = cast::<_, T>(-1 * (i * k) as isize).unwrap()
                * cast(2.0 * f32::consts::PI).unwrap()
                / cast(signal.len()).unwrap();
            let twiddle = Complex::from_polar(&One::one(), &angle);
            sum = sum + twiddle * x;
        }
        *spec_bin = sum;
    }
}

/// Factors an integer into its prime factors.
fn factor(n: usize) -> Vec<(usize, usize)> {
    let mut factors = Vec::new();
    let mut next = n;
    while next > 1 {
        for div in 2..next + 1 {
            if next % div == 0 {
                next = next / div;
                factors.push((div, next));
                break;
            }
        }
    }
    return factors;
}

// returns true if n is a power of 2, false otherwise
fn is_power_of_two(n: usize) -> bool {
    return n & n - 1 == 0;
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Host Info
//!
//! This crate makes available information about the computer,
//! operating system and software that is running.
//!
//! All of the functionality is presented by traits which are
//! implemented by a `HostInfo` struct.
//!
//! ```rust
//! use hostinfo::{HostInfo, UptimeInfo};
//!
//! let hi = HostInfo::new();
//! let uptime = hi.uptime();
//! ```
#![warn(missing_docs)]
#![deny(trivial_numeric_casts, unstable_features,
        unused_import_braces, unused_qualifications)]

extern crate core_foundation;
extern crate libc;

mod sys;
pub use self::sys::HostInfo;

mod hardwareinfo;
pub use self::hardwareinfo::HardwareInfo;

mod kernellimits;
pub use self::kernellimits::KernelLimits;

mod powerinfo;
pub use self::powerinfo::{BatteryInfo, PowerInfo, PowerSource};

mod swapinfo;
pub use self::swapinfo::{SwapInfo, SwapUsage};

mod uptimeinfo;
pub use self::uptimeinfo::UptimeInfo;
<commit_msg>Include core_foundation crate on macOS only.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Host Info
//!
//! This crate makes available information about the computer,
//! operating system and software that is running.
//!
//! All of the functionality is presented by traits which are
//! implemented by a `HostInfo` struct.
//!
//! ```rust
//! use hostinfo::{HostInfo, UptimeInfo};
//!
//! let hi = HostInfo::new();
//! let uptime = hi.uptime();
//! ```
#![warn(missing_docs)]
#![deny(trivial_numeric_casts, unstable_features,
        unused_import_braces, unused_qualifications)]

#[cfg(target_os = "macos")]
extern crate core_foundation;
extern crate libc;

mod sys;
pub use self::sys::HostInfo;

mod hardwareinfo;
pub use self::hardwareinfo::HardwareInfo;

mod kernellimits;
pub use self::kernellimits::KernelLimits;

mod powerinfo;
pub use self::powerinfo::{BatteryInfo, PowerInfo, PowerSource};

mod swapinfo;
pub use self::swapinfo::{SwapInfo, SwapUsage};

mod uptimeinfo;
pub use self::uptimeinfo::UptimeInfo;
<|endoftext|>