<commit_before>use std::ffi::CString;
use std::fmt;
use std::path::Path;

use FormError;
use curl_sys;
use easy::{list, List};

/// Multipart/formdata for an HTTP POST request.
///
/// This structure is built up and then passed to the `Easy::httppost` method to
/// be sent off with a request.
pub struct Form {
    head: *mut curl_sys::curl_httppost,
    tail: *mut curl_sys::curl_httppost,
    headers: Vec<List>,
    buffers: Vec<Vec<u8>>,
    strings: Vec<CString>,
}

/// One part in a multipart upload, added to a `Form`.
pub struct Part<'form, 'data> {
    form: &'form mut Form,
    name: &'data str,
    array: Vec<curl_sys::curl_forms>,
    error: Option<FormError>,
}

pub fn raw(form: &Form) -> *mut curl_sys::curl_httppost {
    form.head
}

impl Form {
    /// Creates a new blank form ready for the addition of new data.
    pub fn new() -> Form {
        Form {
            head: 0 as *mut _,
            tail: 0 as *mut _,
            headers: Vec::new(),
            buffers: Vec::new(),
            strings: Vec::new(),
        }
    }

    /// Prepares adding a new part to this `Form`
    ///
    /// Note that the part is not actually added to the form until the `add`
    /// method is called on `Part`, which may or may not fail.
    pub fn part<'a, 'data>(&'a mut self, name: &'data str) -> Part<'a, 'data> {
        Part {
            error: None,
            form: self,
            name: name,
            array: vec![curl_sys::curl_forms {
                option: curl_sys::CURLFORM_END,
                value: 0 as *mut _,
            }],
        }
    }
}

impl fmt::Debug for Form {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: fill this out more
        f.debug_struct("Form")
         .field("fields", &"...")
         .finish()
    }
}

impl Drop for Form {
    fn drop(&mut self) {
        unsafe {
            curl_sys::curl_formfree(self.head);
        }
    }
}

impl<'form, 'data> Part<'form, 'data> {
    /// A pointer to the contents of this part, the actual data to send away.
    pub fn contents(&mut self, contents: &'data [u8]) -> &mut Self {
        let pos = self.array.len() - 1;
        self.array.insert(pos, curl_sys::curl_forms {
            option: curl_sys::CURLFORM_COPYCONTENTS,
            value: contents.as_ptr() as *mut _,
        });
        self.array.insert(pos + 1, curl_sys::curl_forms {
            option: curl_sys::CURLFORM_CONTENTSLENGTH,
            value: contents.len() as *mut _,
        });
        self
    }

    /// Causes this file to be read and its contents used as data in this part
    ///
    /// This part does not automatically become a file upload part simply
    /// because its data was read from a file.
    ///
    /// # Errors
    ///
    /// If the filename has any internal nul bytes or if on Windows it does not
    /// contain a unicode filename then the `add` function will eventually
    /// return an error.
    pub fn file_content<P>(&mut self, file: P) -> &mut Self
        where P: AsRef<Path>
    {
        self._file_content(file.as_ref())
    }

    fn _file_content(&mut self, file: &Path) -> &mut Self {
        if let Some(bytes) = self.path2cstr(file) {
            let pos = self.array.len() - 1;
            self.array.insert(pos, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_FILECONTENT,
                value: bytes.as_ptr() as *mut _,
            });
            self.form.strings.push(bytes);
        }
        self
    }

    /// Makes this part a file upload part of the given file.
    ///
    /// Sets the filename field to the basename of the provided file name, and
    /// it reads the contents of the file and passes them as data and sets the
    /// content type if the given file matches one of the internally known file
    /// extensions.
    ///
    /// The given upload file must exist entirely on the filesystem before the
    /// upload is started because libcurl needs to read the size of it
    /// beforehand.
    ///
    /// Multiple files can be uploaded by calling this method multiple times and
    /// content types can also be configured for each file (by calling that
    /// next).
    ///
    /// # Errors
    ///
    /// If the filename has any internal nul bytes or if on Windows it does not
    /// contain a unicode filename then this function will cause `add` to return
    /// an error when called.
    pub fn file<P: ?Sized>(&mut self, file: &'data P) -> &mut Self
        where P: AsRef<Path>
    {
        self._file(file.as_ref())
    }

    fn _file(&mut self, file: &'data Path) -> &mut Self {
        if let Some(bytes) = self.path2cstr(file) {
            let pos = self.array.len() - 1;
            self.array.insert(pos, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_FILE,
                value: bytes.as_ptr() as *mut _,
            });
            self.form.strings.push(bytes);
        }
        self
    }

    /// Used in combination with `Part::file`, provides the content-type for
    /// this part, possibly instead of choosing an internal one.
    ///
    /// # Panics
    ///
    /// This function will panic if `content_type` contains an internal nul
    /// byte.
    pub fn content_type(&mut self, content_type: &'data str) -> &mut Self {
        if let Some(bytes) = self.bytes2cstr(content_type.as_bytes()) {
            let pos = self.array.len() - 1;
            self.array.insert(pos, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_CONTENTTYPE,
                value: bytes.as_ptr() as *mut _,
            });
            self.form.strings.push(bytes);
        }
        self
    }

    /// Used in combination with `Part::file`, provides the filename for
    /// this part instead of the actual one.
    ///
    /// # Errors
    ///
    /// If `name` contains an internal nul byte, or if on Windows the path is
    /// not valid unicode then this function will return an error when `add` is
    /// called.
    pub fn filename<P: ?Sized>(&mut self, name: &'data P) -> &mut Self
        where P: AsRef<Path>
    {
        self._filename(name.as_ref())
    }

    fn _filename(&mut self, name: &'data Path) -> &mut Self {
        if let Some(bytes) = self.path2cstr(name) {
            let pos = self.array.len() - 1;
            self.array.insert(pos, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_FILENAME,
                value: bytes.as_ptr() as *mut _,
            });
            self.form.strings.push(bytes);
        }
        self
    }

    /// This is used to provide a custom file upload part without using the
    /// `file` method above.
    ///
    /// The first parameter is for the filename field and the second is the
    /// in-memory contents.
    ///
    /// # Errors
    ///
    /// If `name` contains an internal nul byte, or if on Windows the path is
    /// not valid unicode then this function will return an error when `add` is
    /// called.
    pub fn buffer<P: ?Sized>(&mut self, name: &'data P, data: Vec<u8>)
                             -> &mut Self
        where P: AsRef<Path>
    {
        self._buffer(name.as_ref(), data)
    }

    fn _buffer(&mut self, name: &'data Path, data: Vec<u8>) -> &mut Self {
        if let Some(bytes) = self.path2cstr(name) {
            let pos = self.array.len() - 1;
            self.array.insert(pos, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_BUFFER,
                value: bytes.as_ptr() as *mut _,
            });
            self.form.strings.push(bytes);
            self.array.insert(pos + 1, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_BUFFERPTR,
                value: data.as_ptr() as *mut _,
            });
            self.array.insert(pos + 2, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_BUFFERLENGTH,
                value: data.len() as *mut _,
            });
            self.form.buffers.push(data);
        }
        self
    }

    /// Specifies extra headers for the form POST section.
    ///
    /// Appends the list of headers to those libcurl automatically generates.
    pub fn content_header(&mut self, headers: List) -> &mut Self {
        let pos = self.array.len() - 1;
        self.array.insert(pos, curl_sys::curl_forms {
            option: curl_sys::CURLFORM_CONTENTHEADER,
            value: list::raw(&headers) as *mut _,
        });
        self.form.headers.push(headers);
        self
    }

    /// Attempts to add this part to the `Form` that it was created from.
    ///
    /// If any error happens while adding, that error is returned, otherwise
    /// `Ok(())` is returned.
    pub fn add(&mut self) -> Result<(), FormError> {
        if let Some(err) = self.error.clone() {
            return Err(err)
        }
        let rc = unsafe {
            curl_sys::curl_formadd(&mut self.form.head,
                                   &mut self.form.tail,
                                   curl_sys::CURLFORM_COPYNAME,
                                   self.name.as_ptr(),
                                   curl_sys::CURLFORM_NAMELENGTH,
                                   self.name.len(),
                                   curl_sys::CURLFORM_ARRAY,
                                   self.array.as_ptr(),
                                   curl_sys::CURLFORM_END)
        };
        if rc == curl_sys::CURL_FORMADD_OK {
            Ok(())
        } else {
            Err(FormError::new(rc))
        }
    }

    #[cfg(unix)]
    fn path2cstr(&mut self, p: &Path) -> Option<CString> {
        use std::os::unix::prelude::*;
        self.bytes2cstr(p.as_os_str().as_bytes())
    }

    #[cfg(windows)]
    fn path2cstr(&mut self, p: &Path) -> Option<CString> {
        match p.to_str() {
            Some(bytes) => self.bytes2cstr(bytes.as_bytes()),
            None if self.error.is_none() => {
                // TODO: better error code
                self.error = Some(FormError::new(curl_sys::CURL_FORMADD_INCOMPLETE));
                None
            }
            None => None,
        }
    }

    fn bytes2cstr(&mut self, bytes: &[u8]) -> Option<CString> {
        match CString::new(bytes) {
            Ok(c) => Some(c),
            Err(..) if self.error.is_none() => {
                // TODO: better error code
                self.error = Some(FormError::new(curl_sys::CURL_FORMADD_INCOMPLETE));
                None
            }
            Err(..) => None,
        }
    }
}

impl<'form, 'data> fmt::Debug for Part<'form, 'data> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: fill this out more
        f.debug_struct("Part")
         .field("name", &self.name)
         .field("form", &self.form)
         .finish()
    }
}
<commit_msg>Pass null as form contents if length is empty<commit_after>use std::ffi::CString;
use std::fmt;
use std::path::Path;

use FormError;
use curl_sys;
use easy::{list, List};

/// Multipart/formdata for an HTTP POST request.
///
/// This structure is built up and then passed to the `Easy::httppost` method to
/// be sent off with a request.
pub struct Form {
    head: *mut curl_sys::curl_httppost,
    tail: *mut curl_sys::curl_httppost,
    headers: Vec<List>,
    buffers: Vec<Vec<u8>>,
    strings: Vec<CString>,
}

/// One part in a multipart upload, added to a `Form`.
pub struct Part<'form, 'data> {
    form: &'form mut Form,
    name: &'data str,
    array: Vec<curl_sys::curl_forms>,
    error: Option<FormError>,
}

pub fn raw(form: &Form) -> *mut curl_sys::curl_httppost {
    form.head
}

impl Form {
    /// Creates a new blank form ready for the addition of new data.
    pub fn new() -> Form {
        Form {
            head: 0 as *mut _,
            tail: 0 as *mut _,
            headers: Vec::new(),
            buffers: Vec::new(),
            strings: Vec::new(),
        }
    }

    /// Prepares adding a new part to this `Form`
    ///
    /// Note that the part is not actually added to the form until the `add`
    /// method is called on `Part`, which may or may not fail.
    pub fn part<'a, 'data>(&'a mut self, name: &'data str) -> Part<'a, 'data> {
        Part {
            error: None,
            form: self,
            name: name,
            array: vec![curl_sys::curl_forms {
                option: curl_sys::CURLFORM_END,
                value: 0 as *mut _,
            }],
        }
    }
}

impl fmt::Debug for Form {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: fill this out more
        f.debug_struct("Form")
         .field("fields", &"...")
         .finish()
    }
}

impl Drop for Form {
    fn drop(&mut self) {
        unsafe {
            curl_sys::curl_formfree(self.head);
        }
    }
}

impl<'form, 'data> Part<'form, 'data> {
    /// A pointer to the contents of this part, the actual data to send away.
    pub fn contents(&mut self, contents: &'data [u8]) -> &mut Self {
        let pos = self.array.len() - 1;

        // curl has an oddity where if the length if 0 it will call strlen
        // on the value.  This means that if someone wants to add empty form
        // contents we need to make sure the buffer contains a null byte.
        let ptr = if contents.is_empty() {
            b"\x00"
        } else {
            contents
        }.as_ptr();

        self.array.insert(pos, curl_sys::curl_forms {
            option: curl_sys::CURLFORM_COPYCONTENTS,
            value: ptr as *mut _,
        });
        self.array.insert(pos + 1, curl_sys::curl_forms {
            option: curl_sys::CURLFORM_CONTENTSLENGTH,
            value: contents.len() as *mut _,
        });
        self
    }

    /// Causes this file to be read and its contents used as data in this part
    ///
    /// This part does not automatically become a file upload part simply
    /// because its data was read from a file.
    ///
    /// # Errors
    ///
    /// If the filename has any internal nul bytes or if on Windows it does not
    /// contain a unicode filename then the `add` function will eventually
    /// return an error.
    pub fn file_content<P>(&mut self, file: P) -> &mut Self
        where P: AsRef<Path>
    {
        self._file_content(file.as_ref())
    }

    fn _file_content(&mut self, file: &Path) -> &mut Self {
        if let Some(bytes) = self.path2cstr(file) {
            let pos = self.array.len() - 1;
            self.array.insert(pos, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_FILECONTENT,
                value: bytes.as_ptr() as *mut _,
            });
            self.form.strings.push(bytes);
        }
        self
    }

    /// Makes this part a file upload part of the given file.
    ///
    /// Sets the filename field to the basename of the provided file name, and
    /// it reads the contents of the file and passes them as data and sets the
    /// content type if the given file matches one of the internally known file
    /// extensions.
    ///
    /// The given upload file must exist entirely on the filesystem before the
    /// upload is started because libcurl needs to read the size of it
    /// beforehand.
    ///
    /// Multiple files can be uploaded by calling this method multiple times and
    /// content types can also be configured for each file (by calling that
    /// next).
    ///
    /// # Errors
    ///
    /// If the filename has any internal nul bytes or if on Windows it does not
    /// contain a unicode filename then this function will cause `add` to return
    /// an error when called.
    pub fn file<P: ?Sized>(&mut self, file: &'data P) -> &mut Self
        where P: AsRef<Path>
    {
        self._file(file.as_ref())
    }

    fn _file(&mut self, file: &'data Path) -> &mut Self {
        if let Some(bytes) = self.path2cstr(file) {
            let pos = self.array.len() - 1;
            self.array.insert(pos, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_FILE,
                value: bytes.as_ptr() as *mut _,
            });
            self.form.strings.push(bytes);
        }
        self
    }

    /// Used in combination with `Part::file`, provides the content-type for
    /// this part, possibly instead of choosing an internal one.
    ///
    /// # Panics
    ///
    /// This function will panic if `content_type` contains an internal nul
    /// byte.
    pub fn content_type(&mut self, content_type: &'data str) -> &mut Self {
        if let Some(bytes) = self.bytes2cstr(content_type.as_bytes()) {
            let pos = self.array.len() - 1;
            self.array.insert(pos, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_CONTENTTYPE,
                value: bytes.as_ptr() as *mut _,
            });
            self.form.strings.push(bytes);
        }
        self
    }

    /// Used in combination with `Part::file`, provides the filename for
    /// this part instead of the actual one.
    ///
    /// # Errors
    ///
    /// If `name` contains an internal nul byte, or if on Windows the path is
    /// not valid unicode then this function will return an error when `add` is
    /// called.
    pub fn filename<P: ?Sized>(&mut self, name: &'data P) -> &mut Self
        where P: AsRef<Path>
    {
        self._filename(name.as_ref())
    }

    fn _filename(&mut self, name: &'data Path) -> &mut Self {
        if let Some(bytes) = self.path2cstr(name) {
            let pos = self.array.len() - 1;
            self.array.insert(pos, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_FILENAME,
                value: bytes.as_ptr() as *mut _,
            });
            self.form.strings.push(bytes);
        }
        self
    }

    /// This is used to provide a custom file upload part without using the
    /// `file` method above.
    ///
    /// The first parameter is for the filename field and the second is the
    /// in-memory contents.
    ///
    /// # Errors
    ///
    /// If `name` contains an internal nul byte, or if on Windows the path is
    /// not valid unicode then this function will return an error when `add` is
    /// called.
    pub fn buffer<P: ?Sized>(&mut self, name: &'data P, data: Vec<u8>)
                             -> &mut Self
        where P: AsRef<Path>
    {
        self._buffer(name.as_ref(), data)
    }

    fn _buffer(&mut self, name: &'data Path, data: Vec<u8>) -> &mut Self {
        if let Some(bytes) = self.path2cstr(name) {
            let pos = self.array.len() - 1;
            self.array.insert(pos, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_BUFFER,
                value: bytes.as_ptr() as *mut _,
            });
            self.form.strings.push(bytes);
            self.array.insert(pos + 1, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_BUFFERPTR,
                value: data.as_ptr() as *mut _,
            });
            self.array.insert(pos + 2, curl_sys::curl_forms {
                option: curl_sys::CURLFORM_BUFFERLENGTH,
                value: data.len() as *mut _,
            });
            self.form.buffers.push(data);
        }
        self
    }

    /// Specifies extra headers for the form POST section.
    ///
    /// Appends the list of headers to those libcurl automatically generates.
    pub fn content_header(&mut self, headers: List) -> &mut Self {
        let pos = self.array.len() - 1;
        self.array.insert(pos, curl_sys::curl_forms {
            option: curl_sys::CURLFORM_CONTENTHEADER,
            value: list::raw(&headers) as *mut _,
        });
        self.form.headers.push(headers);
        self
    }

    /// Attempts to add this part to the `Form` that it was created from.
    ///
    /// If any error happens while adding, that error is returned, otherwise
    /// `Ok(())` is returned.
    pub fn add(&mut self) -> Result<(), FormError> {
        if let Some(err) = self.error.clone() {
            return Err(err)
        }
        let rc = unsafe {
            curl_sys::curl_formadd(&mut self.form.head,
                                   &mut self.form.tail,
                                   curl_sys::CURLFORM_COPYNAME,
                                   self.name.as_ptr(),
                                   curl_sys::CURLFORM_NAMELENGTH,
                                   self.name.len(),
                                   curl_sys::CURLFORM_ARRAY,
                                   self.array.as_ptr(),
                                   curl_sys::CURLFORM_END)
        };
        if rc == curl_sys::CURL_FORMADD_OK {
            Ok(())
        } else {
            Err(FormError::new(rc))
        }
    }

    #[cfg(unix)]
    fn path2cstr(&mut self, p: &Path) -> Option<CString> {
        use std::os::unix::prelude::*;
        self.bytes2cstr(p.as_os_str().as_bytes())
    }

    #[cfg(windows)]
    fn path2cstr(&mut self, p: &Path) -> Option<CString> {
        match p.to_str() {
            Some(bytes) => self.bytes2cstr(bytes.as_bytes()),
            None if self.error.is_none() => {
                // TODO: better error code
                self.error = Some(FormError::new(curl_sys::CURL_FORMADD_INCOMPLETE));
                None
            }
            None => None,
        }
    }

    fn bytes2cstr(&mut self, bytes: &[u8]) -> Option<CString> {
        match CString::new(bytes) {
            Ok(c) => Some(c),
            Err(..) if self.error.is_none() => {
                // TODO: better error code
                self.error = Some(FormError::new(curl_sys::CURL_FORMADD_INCOMPLETE));
                None
            }
            Err(..) => None,
        }
    }
}

impl<'form, 'data> fmt::Debug for Part<'form, 'data> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: fill this out more
        f.debug_struct("Part")
         .field("name", &self.name)
         .field("form", &self.form)
         .finish()
    }
}
<|endoftext|>


<commit_before>//! Binary lambda calculus execution

use binary_encoding::{from_binary};
use lambda_encoding::{encode, decode};
use lambda_calculus::reduction::beta_full;
use self::Error::*;

/// An error that can occur during blc execution.
#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidProgram
}

/// Executes a binary lambda calculus program, feeding it the given argument.
///
/// # Example
/// ```
/// use blc::execution::run;
///
/// let reverse = b"00 01 01 10 01 00 01 10 10 00 00 00 00 01 01 110\
///                 01 11110 11110 00 01 01 10 11110 110 00 00 10";
///
/// assert_eq!(run(&*reverse, b"herp derp"), Ok("pred preh".into()));
/// ```
pub fn run(blc_program: &[u8], blc_argument: &[u8]) -> Result<String, Error> {
    let program = from_binary(blc_program);
    if program.is_err() { return Err(InvalidProgram) }
    let argument = encode(blc_argument);
    let calculation = beta_full(program.unwrap().app(argument)); // safe

    Ok(decode(calculation))
}

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

    #[test]
    fn id() {
        let id     = b" ";
        let id_blc = decompress(&*id);
        let input  = b"herp derp";

        assert_eq!(run(&*id_blc, &*input).unwrap(), "herp derp".to_owned());
    }

    #[test]
    fn sort() {
        let sort =
            [0x15, 0x46, 0x84, 0x06, 0x05, 0x46, 0x81, 0x60, 0x15, 0xfb, 0xec, 0x2f, 0x80, 0x01,
             0x5b, 0xf9, 0x7f, 0x0b, 0x7e, 0xf7, 0x2f, 0xec, 0x2d, 0xfb, 0x80, 0x56, 0x05, 0xfd,
             0x85, 0xbb, 0x76, 0x11, 0x5d, 0x50, 0x5c, 0x00, 0xbe, 0x7f, 0xc1, 0x2b, 0xff, 0x0f,
             0xfc, 0x2c, 0x1b, 0x72, 0xbf, 0xf0, 0xff, 0xc2, 0xc1, 0x6d, 0x34, 0x50, 0x40];

        let sort_blc = decompress(&sort);
        let input  = b"3241";

        assert_eq!(run(&*sort_blc, &*input).unwrap(), "1234".to_owned());
    }

    #[test]
    fn inflating() {
        // program code from http://www.ioccc.org/2012/tromp/inflate.Blc
        let inflate_compressed =
            [0x44, 0x44, 0x68, 0x16, 0x01, 0x79, 0x1a, 0x00, 0x16, 0x7f, 0xfb, 0xcb, 0xcf, 0xdf,
             0x65, 0xfb, 0xed, 0x0f, 0x3c, 0xe7, 0x3c, 0xf3, 0xc2, 0xd8, 0x20, 0x58, 0x2c, 0x0b,
             0x06, 0xc0];

        let inflate_blc = decompress(&inflate_compressed);
        let s_compressed = [0x1, 0x7a, 0x74];

        assert_eq!(run(&*inflate_blc, &s_compressed[..]).unwrap(), "000000010111101001110100".to_owned());
    }

    #[test]
    fn deflating() {
        // program code from http://www.ioccc.org/2012/tromp/deflate.Blc
        let deflate_compressed =
            [0x44, 0x68, 0x16, 0x05, 0x7e, 0x01, 0x17, 0x00, 0xbe, 0x55, 0xff, 0xf0, 0x0d, 0xc1,
             0x8b, 0xb2, 0xc1, 0xb0, 0xf8, 0x7c, 0x2d, 0xd8, 0x05, 0x9e, 0x09, 0x7f, 0xbf, 0xb1,
             0x48, 0x39, 0xce, 0x81, 0xce, 0x80];

        let deflate_blc = decompress(&deflate_compressed);
        let s_blc = b"00000001011110100111010";

        assert_eq!(run(&*deflate_blc, &s_blc[..]).unwrap().as_bytes(), [0x1, 0x7a, 0x74]);
    }
/*
    #[test] /* WIP; this one parses properly, but doesn't return the expected result */
    fn hilbert() {
        // program code from http://www.ioccc.org/2012/tromp/hilbert.Blc
        let hilbert_compressed =
            [0x18, 0x18, 0x18, 0x18, 0x11, 0x11, 0x54, 0x68, 0x06, 0x04, 0x15, 0x5f, 0xf0, 0x41,
             0x9d, 0xf9, 0xde, 0x16, 0xff, 0xfe, 0x5f, 0x3f, 0xef, 0xf6, 0x15, 0xff, 0x94, 0x68,
             0x40, 0x58, 0x11, 0x7e, 0x05, 0xcb, 0xfe, 0xbc, 0xbf, 0xee, 0x86, 0xcb, 0x94, 0x68,
             0x16, 0x00, 0x5c, 0x0b, 0xfa, 0xcb, 0xfb, 0xf7, 0x1a, 0x85, 0xe0, 0x5c, 0xf4, 0x14,
             0xd5, 0xfe, 0x08, 0x18, 0x0b, 0x04, 0x8d, 0x08, 0x00, 0xe0, 0x78, 0x01, 0x64, 0x45,
             0xff, 0xe5, 0xff, 0x7f, 0xff, 0xfe, 0x5f, 0xff, 0x2f, 0xc0, 0x2f, 0x7a, 0xd9, 0x7f,
             0x5b, 0xff, 0xff, 0xfb, 0xff, 0xfc, 0xaa, 0xff, 0xf7, 0x81, 0x7f, 0xfa, 0xdf, 0x76,
             0x69, 0x54, 0x68, 0x06, 0x01, 0x57, 0xf7, 0xe1, 0x60, 0x5c, 0x13, 0xfe, 0x80, 0xb2,
             0x2c, 0x18, 0x58, 0x1b, 0xfe, 0x5c, 0x10, 0x42, 0xff, 0x80, 0x5d, 0xee, 0xc0, 0x6c,
             0x2c, 0x0c, 0x06, 0x08, 0x19, 0x1a, 0x00, 0x16, 0x7f, 0xbc, 0xbc, 0xfd, 0xf6, 0x5f,
             0x7c, 0x0a, 0x20];

        let hilbert_blc = decompress(&hilbert_compressed);
        let arg = b"1234";

        assert_eq!(run(&hilbert_blc[..], &arg[..]), Ok("WIP".into()));
    }
*/
/*
    #[test] /* WIP; looks like Tromp's interpreter code is borked, it doesn't parse properly */
    fn brainfuck() {
        // program code from http://www.ioccc.org/2012/tromp/bf.Blc
        let bf_interpreter_compressed =
            [0x01, 0xa1, 0x51, 0x44, 0x02, 0xd5, 0x55, 0x84, 0x22, 0x30, 0x70, 0xb7, 0x00, 0xf0,
             0x32, 0xff, 0x7f, 0x85, 0xf9, 0xbf, 0x95, 0x6f, 0xe1, 0x5e, 0xc0, 0xee, 0x7d, 0x7f,
             0x00, 0x68, 0x54, 0xe5, 0xfb, 0xfd, 0x55, 0x58, 0xfd, 0x57, 0x45, 0xe0, 0xb6, 0xf0,
             0xfb, 0xeb, 0x07, 0xd6, 0x2f, 0xf0, 0xd7, 0x73, 0x6f, 0xe1, 0xc0, 0xbc, 0x14, 0xf1,
             0x1f, 0x2e, 0xff, 0x0b, 0x17, 0x66, 0x6f, 0xa1, 0x2f, 0xef, 0x5b, 0xe8, 0xff, 0x13,
             0xff, 0xcf, 0x20, 0x34, 0xca, 0xe1, 0x0b, 0xd0, 0xc8, 0x0a, 0xe5, 0x1f, 0xee, 0x99,
             0x6a, 0x5a, 0x7f, 0xff, 0xff, 0x0f, 0xff, 0x1f, 0xd0, 0x04, 0x9d, 0x87, 0xdb, 0x05,
             0x00, 0xab, 0x3b, 0xb7, 0x40, 0x23, 0xb0, 0xc0, 0xcc, 0x28, 0x10, 0x74, 0x0e, 0x6c];

        let bf_interpreter_blc = decompress(&bf_interpreter_compressed);
        let bf_hello =
            b"++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.]";

        assert_eq!(run(&bf_interpreter_blc, &bf_hello[..]), Ok("Hello World!".into()));
    }
*/
}
<commit_msg>add different bf_interpreter code<commit_after>//! Binary lambda calculus execution

use binary_encoding::{from_binary};
use lambda_encoding::{encode, decode};
use lambda_calculus::reduction::beta_full;
use self::Error::*;

/// An error that can occur during blc execution.
#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidProgram
}

/// Executes a binary lambda calculus program, feeding it the given argument.
///
/// # Example
/// ```
/// use blc::execution::run;
///
/// let reverse = b"00 01 01 10 01 00 01 10 10 00 00 00 00 01 01 110\
///                 01 11110 11110 00 01 01 10 11110 110 00 00 10";
///
/// assert_eq!(run(&*reverse, b"herp derp"), Ok("pred preh".into()));
/// ```
pub fn run(blc_program: &[u8], blc_argument: &[u8]) -> Result<String, Error> {
    let program = from_binary(blc_program);
    if program.is_err() { return Err(InvalidProgram) }
    let argument = encode(blc_argument);
    let calculation = beta_full(program.unwrap().app(argument)); // safe

    Ok(decode(calculation))
}

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

    #[test]
    fn id() {
        let id     = b" ";
        let id_blc = decompress(&*id);
        let input  = b"herp derp";

        assert_eq!(run(&*id_blc, &*input).unwrap(), "herp derp".to_owned());
    }

    #[test]
    fn sort() {
        let sort =
            [0x15, 0x46, 0x84, 0x06, 0x05, 0x46, 0x81, 0x60, 0x15, 0xfb, 0xec, 0x2f, 0x80, 0x01,
             0x5b, 0xf9, 0x7f, 0x0b, 0x7e, 0xf7, 0x2f, 0xec, 0x2d, 0xfb, 0x80, 0x56, 0x05, 0xfd,
             0x85, 0xbb, 0x76, 0x11, 0x5d, 0x50, 0x5c, 0x00, 0xbe, 0x7f, 0xc1, 0x2b, 0xff, 0x0f,
             0xfc, 0x2c, 0x1b, 0x72, 0xbf, 0xf0, 0xff, 0xc2, 0xc1, 0x6d, 0x34, 0x50, 0x40];

        let sort_blc = decompress(&sort);
        let input  = b"3241";

        assert_eq!(run(&*sort_blc, &*input).unwrap(), "1234".to_owned());
    }

    #[test]
    fn inflating() {
        // program code from http://www.ioccc.org/2012/tromp/inflate.Blc
        let inflate_compressed =
            [0x44, 0x44, 0x68, 0x16, 0x01, 0x79, 0x1a, 0x00, 0x16, 0x7f, 0xfb, 0xcb, 0xcf, 0xdf,
             0x65, 0xfb, 0xed, 0x0f, 0x3c, 0xe7, 0x3c, 0xf3, 0xc2, 0xd8, 0x20, 0x58, 0x2c, 0x0b,
             0x06, 0xc0];

        let inflate_blc = decompress(&inflate_compressed);
        let s_compressed = [0x1, 0x7a, 0x74];

        assert_eq!(run(&*inflate_blc, &s_compressed[..]).unwrap(), "000000010111101001110100".to_owned());
    }

    #[test]
    fn deflating() {
        // program code from http://www.ioccc.org/2012/tromp/deflate.Blc
        let deflate_compressed =
            [0x44, 0x68, 0x16, 0x05, 0x7e, 0x01, 0x17, 0x00, 0xbe, 0x55, 0xff, 0xf0, 0x0d, 0xc1,
             0x8b, 0xb2, 0xc1, 0xb0, 0xf8, 0x7c, 0x2d, 0xd8, 0x05, 0x9e, 0x09, 0x7f, 0xbf, 0xb1,
             0x48, 0x39, 0xce, 0x81, 0xce, 0x80];

        let deflate_blc = decompress(&deflate_compressed);
        let s_blc = b"00000001011110100111010";

        assert_eq!(run(&*deflate_blc, &s_blc[..]).unwrap().as_bytes(), [0x1, 0x7a, 0x74]);
    }
/*
    #[test] /* WIP; this one parses properly, but doesn't return the expected result */
    fn hilbert() {
        // program code from http://www.ioccc.org/2012/tromp/hilbert.Blc
        let hilbert_compressed =
            [0x18, 0x18, 0x18, 0x18, 0x11, 0x11, 0x54, 0x68, 0x06, 0x04, 0x15, 0x5f, 0xf0, 0x41,
             0x9d, 0xf9, 0xde, 0x16, 0xff, 0xfe, 0x5f, 0x3f, 0xef, 0xf6, 0x15, 0xff, 0x94, 0x68,
             0x40, 0x58, 0x11, 0x7e, 0x05, 0xcb, 0xfe, 0xbc, 0xbf, 0xee, 0x86, 0xcb, 0x94, 0x68,
             0x16, 0x00, 0x5c, 0x0b, 0xfa, 0xcb, 0xfb, 0xf7, 0x1a, 0x85, 0xe0, 0x5c, 0xf4, 0x14,
             0xd5, 0xfe, 0x08, 0x18, 0x0b, 0x04, 0x8d, 0x08, 0x00, 0xe0, 0x78, 0x01, 0x64, 0x45,
             0xff, 0xe5, 0xff, 0x7f, 0xff, 0xfe, 0x5f, 0xff, 0x2f, 0xc0, 0x2f, 0x7a, 0xd9, 0x7f,
             0x5b, 0xff, 0xff, 0xfb, 0xff, 0xfc, 0xaa, 0xff, 0xf7, 0x81, 0x7f, 0xfa, 0xdf, 0x76,
             0x69, 0x54, 0x68, 0x06, 0x01, 0x57, 0xf7, 0xe1, 0x60, 0x5c, 0x13, 0xfe, 0x80, 0xb2,
             0x2c, 0x18, 0x58, 0x1b, 0xfe, 0x5c, 0x10, 0x42, 0xff, 0x80, 0x5d, 0xee, 0xc0, 0x6c,
             0x2c, 0x0c, 0x06, 0x08, 0x19, 0x1a, 0x00, 0x16, 0x7f, 0xbc, 0xbc, 0xfd, 0xf6, 0x5f,
             0x7c, 0x0a, 0x20];

        let hilbert_blc = decompress(&hilbert_compressed);
        let arg = b"1234";

        assert_eq!(run(&hilbert_blc[..], &arg[..]), Ok("WIP".into()));
    }
*/
/*
    #[test] /* WIP; the first code doesn't parse properly, the second takes forever */
    fn brainfuck() {
        // program code from http://www.ioccc.org/2012/tromp/bf.Blc
/*        let bf_interpreter_compressed =
            [0x01, 0xa1, 0x51, 0x44, 0x02, 0xd5, 0x55, 0x84, 0x22, 0x30, 0x70, 0xb7, 0x00, 0xf0,
             0x32, 0xff, 0x7f, 0x85, 0xf9, 0xbf, 0x95, 0x6f, 0xe1, 0x5e, 0xc0, 0xee, 0x7d, 0x7f,
             0x00, 0x68, 0x54, 0xe5, 0xfb, 0xfd, 0x55, 0x58, 0xfd, 0x57, 0x45, 0xe0, 0xb6, 0xf0,
             0xfb, 0xeb, 0x07, 0xd6, 0x2f, 0xf0, 0xd7, 0x73, 0x6f, 0xe1, 0xc0, 0xbc, 0x14, 0xf1,
             0x1f, 0x2e, 0xff, 0x0b, 0x17, 0x66, 0x6f, 0xa1, 0x2f, 0xef, 0x5b, 0xe8, 0xff, 0x13,
             0xff, 0xcf, 0x20, 0x34, 0xca, 0xe1, 0x0b, 0xd0, 0xc8, 0x0a, 0xe5, 0x1f, 0xee, 0x99,
             0x6a, 0x5a, 0x7f, 0xff, 0xff, 0x0f, 0xff, 0x1f, 0xd0, 0x04, 0x9d, 0x87, 0xdb, 0x05,
             0x00, 0xab, 0x3b, 0xb7, 0x40, 0x23, 0xb0, 0xc0, 0xcc, 0x28, 0x10, 0x74, 0x0e, 0x6c];*/

        let bf_interpreter_compressed =
            [0x44, 0x51, 0xa1, 0x01, 0x84, 0x55, 0xd5, 0x02, 0xb7, 0x70, 0x30, 0x22, 0xff, 0x32,
             0xf0, 0x00, 0xbf, 0xf9, 0x85, 0x7f, 0x5e, 0xe1, 0x6f, 0x95, 0x7f, 0x7d, 0xee, 0xc0,
             0xe5, 0x54, 0x68, 0x00, 0x58, 0x55, 0xfd, 0xfb, 0xe0, 0x45, 0x57, 0xfd, 0xeb, 0xfb,
             0xf0, 0xb6, 0xf0, 0x2f, 0xd6, 0x07, 0xe1, 0x6f, 0x73, 0xd7, 0xf1, 0x14, 0xbc, 0xc0,
             0x0b, 0xff, 0x2e, 0x1f, 0xa1, 0x6f, 0x66, 0x17, 0xe8, 0x5b, 0xef, 0x2f, 0xcf, 0xff,
             0x13, 0xff, 0xe1, 0xca, 0x34, 0x20, 0x0a, 0xc8, 0xd0, 0x0b, 0x99, 0xee, 0x1f, 0xe5,
             0xff, 0x7f, 0x5a, 0x6a, 0x1f, 0xff, 0x0f, 0xff, 0x87, 0x9d, 0x04, 0xd0, 0xab, 0x00,
             0x05, 0xdb, 0x23, 0x40, 0xb7, 0x3b, 0x28, 0xcc, 0xc0, 0xb0, 0x6c, 0x0e, 0x74, 0x10];

        let bf_interpreter_blc = decompress(&bf_interpreter_compressed);
        let bf_hello =
            b"++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.]";

        assert_eq!(run(&bf_interpreter_blc, &bf_hello[..]), Ok("Hello World!".into()));
    }
*/
}
<|endoftext|>


<commit_before>// Parse ANSI attr code

use regex::Regex;
use curses::{register_ansi, attr_t};
use std::default::Default;

pub struct ANSIParser {
    re: &'static Regex,
    last_attr: Option<attr_t>,
}

lazy_static! {
    static ref ANSI_RE: Regex = Regex::new(r"\x1B\[(?:([0-9]+;[0-9]+[Hf])|([0-9]+[ABCD])|(s|u|2J|K)|([0-9;]*m)|(=[0-9]+[hI]))").unwrap();
}

impl Default for ANSIParser {
    fn default() -> Self {
        ANSIParser {
            re: &ANSI_RE,
            last_attr: None,
        }
    }
}

impl ANSIParser {
    pub fn parse_ansi(&mut self, text: &str) -> (String, Vec<(usize, attr_t)>) {
        let mut strip_string = String::new();
        let mut colors = Vec::new();

        // assume parse_ansi is called linewise.
        // Because ANSI color code can affect text of next lines. We will save the last attribute and
        // add it to the newest line if no new color is specified.
        match self.re.find(text) {
            Some(mat) if mat.start() == 0 => {}
            Some(_) | None => {
                self.last_attr.map(|attr| {
                    colors.push((0, attr));
                });
            }
        }

        let mut num_chars = 0;
        let mut last = 0;
        for mat in self.re.find_iter(text) {
            let (start, end) = (mat.start(), mat.end());
            strip_string.push_str(&text[last..start]);
            num_chars += (&text[last..start]).chars().count();

            last = end;

            let attr = self.interpret_code(&text[start..end]);
            attr.map(|attr| {
                colors.push((num_chars, attr));
            });
            self.last_attr = attr;
        }

        strip_string.push_str(&text[last..text.len()]);

        (strip_string, colors)
    }

    fn interpret_code(&self, code: &str) -> Option<attr_t> {
        let key = register_ansi(code.to_owned());
        Some(key)

        //let mut state256 = 0;
        //let mut attr = 0;
        //let mut fg = -1;
        //let mut bg = -1;
        //let mut use_fg = true;

        //let code = &code[2..code.len()-1]; // ^[[1;30;40m -> 1;30;40
        //if code.is_empty() {
        //return Some(A_NORMAL());
        //}

        //for num in code.split(';').map(|x| x.parse::<i16>()) {
        //match state256 {
        //0 => {
        //match num.unwrap_or(0) {
        //0 => {attr = 0;}
        //1 => {attr |= A_BOLD();}
        //4 => {attr |= A_UNDERLINE();}
        //5 => {attr |= A_BLINK();}
        //7 => {attr |= A_REVERSE();}
        //8 => {attr |= A_INVIS();}
        //38 => {
        //use_fg = true;
        //state256 += 1;
        //}
        //48 => {
        //use_fg = false;
        //state256 += 1;
        //}
        //39 => {
        //fg = -1;
        //}
        //49 => {
        //bg = -1;
        //}
        //num if num >= 30 && num <= 37 => {
        //fg = num - 30;
        //}
        //num if num >= 40 && num <= 47 => {
        //bg = num - 40;
        //}
        //_ => {
        //}
        //}
        //}
        //1 => {
        //match num.unwrap_or(0) {
        //5 => { state256 += 1; }
        //_ => { state256 = 0; }
        //}
        //}
        //2 => {
        //if use_fg {
        //fg = num.unwrap_or(-1);
        //} else {
        //bg = num.unwrap_or(-1);
        //}
        //}
        //_ => {}
        //}
        //}

        //if fg != -1 || bg != -1 {
        //attr |= get_color_pair(fg, bg);
        //}

        //Some(attr)
    }
}

<commit_msg>prohibit ANSI codes that clears the screen/line<commit_after>// Parse ANSI attr code

use regex::Regex;
use curses::{register_ansi, attr_t};
use std::default::Default;

pub struct ANSIParser {
    re: &'static Regex,
    last_attr: Option<attr_t>,
}

lazy_static! {
    static ref ANSI_RE: Regex = Regex::new(r"\x1B\[(?:([0-9]+;[0-9]+[Hf])|([0-9]+[ABCD])|(s|u|2J|K)|([0-9;]*m)|(=[0-9]+[hI]))").unwrap();
}

impl Default for ANSIParser {
    fn default() -> Self {
        ANSIParser {
            re: &ANSI_RE,
            last_attr: None,
        }
    }
}

impl ANSIParser {
    pub fn parse_ansi(&mut self, text: &str) -> (String, Vec<(usize, attr_t)>) {
        let mut strip_string = String::new();
        let mut colors = Vec::new();

        // assume parse_ansi is called linewise.
        // Because ANSI color code can affect text of next lines. We will save the last attribute and
        // add it to the newest line if no new color is specified.
        match self.re.find(text) {
            Some(mat) if mat.start() == 0 => {}
            Some(_) | None => {
                self.last_attr.map(|attr| {
                    colors.push((0, attr));
                });
            }
        }

        let mut num_chars = 0;
        let mut last = 0;
        for mat in self.re.find_iter(text) {
            let (start, end) = (mat.start(), mat.end());
            strip_string.push_str(&text[last..start]);
            num_chars += (&text[last..start]).chars().count();

            last = end;

            let attr = self.interpret_code(&text[start..end]);
            attr.map(|attr| {
                colors.push((num_chars, attr));
            });
            self.last_attr = attr;
        }

        strip_string.push_str(&text[last..text.len()]);

        (strip_string, colors)
    }

    fn interpret_code(&self, code: &str) -> Option<attr_t> {
        if code == "\x1B[K" || code == "\x1B[2J" {
            // clear screen & clear line
            None
        } else {
            let key = register_ansi(code.to_owned());
            Some(key)
        }

        //let mut state256 = 0;
        //let mut attr = 0;
        //let mut fg = -1;
        //let mut bg = -1;
        //let mut use_fg = true;

        //let code = &code[2..code.len()-1]; // ^[[1;30;40m -> 1;30;40
        //if code.is_empty() {
        //return Some(A_NORMAL());
        //}

        //for num in code.split(';').map(|x| x.parse::<i16>()) {
        //match state256 {
        //0 => {
        //match num.unwrap_or(0) {
        //0 => {attr = 0;}
        //1 => {attr |= A_BOLD();}
        //4 => {attr |= A_UNDERLINE();}
        //5 => {attr |= A_BLINK();}
        //7 => {attr |= A_REVERSE();}
        //8 => {attr |= A_INVIS();}
        //38 => {
        //use_fg = true;
        //state256 += 1;
        //}
        //48 => {
        //use_fg = false;
        //state256 += 1;
        //}
        //39 => {
        //fg = -1;
        //}
        //49 => {
        //bg = -1;
        //}
        //num if num >= 30 && num <= 37 => {
        //fg = num - 30;
        //}
        //num if num >= 40 && num <= 47 => {
        //bg = num - 40;
        //}
        //_ => {
        //}
        //}
        //}
        //1 => {
        //match num.unwrap_or(0) {
        //5 => { state256 += 1; }
        //_ => { state256 = 0; }
        //}
        //}
        //2 => {
        //if use_fg {
        //fg = num.unwrap_or(-1);
        //} else {
        //bg = num.unwrap_or(-1);
        //}
        //}
        //_ => {}
        //}
        //}

        //if fg != -1 || bg != -1 {
        //attr |= get_color_pair(fg, bg);
        //}

        //Some(attr)
    }
}

<|endoftext|>


<commit_before>//! Axis enum for indexing three-dimensional structures.

use std::ops::{Index, IndexMut};
use std::fmt::{Display, Formatter, Result};

/// An `Axis` in a three-dimensional coordinate system.
/// Used to access `Vector3`/`Point3` structs via index.
///
/// # Example
/// ```
/// use bvh::axis::Axis;
///
/// let mut position = [1.0, 0.5, 42.0];
/// position[Axis::Y] *= 4.0;
///
/// assert_eq!(position[Axis::Y], 2.0);
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Axis {
    /// Index of the X axis.
    X = 0,

    /// Index of the Y axis.
    Y = 1,

    /// Index of the Z axis.
    Z = 2,
}

/// Make three-dimensional arrays indexable by `Axis`.
impl Index<Axis> for [f32; 3] {
    type Output = f32;

    fn index(&self, axis: Axis) -> &f32 {
        &self[axis as usize]
    }
}

/// Make three-dimensional arrays mutably accessible by `Axis`.
impl IndexMut<Axis> for [f32; 3] {
    fn index_mut(&mut self, axis: Axis) -> &mut f32 {
        &mut self[axis as usize]
    }
}

/// Display implementation for `Axis`.
impl Display for Axis {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let c = match *self {
            Axis::X => "x",
            Axis::Y => "y",
            Axis::Z => "z",
        };
        write!(f, "{}", c)
    }
}

#[cfg(test)]
mod test {
    use axis::Axis;

    /// Test whether accessing arrays by index is the same as accessing them by `Axis`.
    quickcheck!{
        fn test_index_by_axis(tpl: (f32, f32, f32)) -> bool {
            let a = [tpl.0, tpl.1, tpl.2];

            a[0] == a[Axis::X] && a[1] == a[Axis::Y] && a[2] == a[Axis::Z]
        }
    }

    quickcheck!{
        fn test_set_by_axis(tpl: (f32, f32, f32)) -> bool {
            let mut a = [0.0, 0.0, 0.0];

            a[Axis::X] = tpl.0;
            a[Axis::Y] = tpl.1;
            a[Axis::Z] = tpl.2;

            a[0] == tpl.0 && a[1] == tpl.1 && a[2] == tpl.2
        }
    }
}
<commit_msg>Add examples and change instances from arrays to slices<commit_after>//! Axis enum for indexing three-dimensional structures.

use std::ops::{Index, IndexMut};
use std::fmt::{Display, Formatter, Result};

/// An `Axis` in a three-dimensional coordinate system.
/// Used to access `Vector3`/`Point3` structs via index.
///
/// # Examples
/// ```
/// use bvh::axis::Axis;
///
/// let mut position = [1.0, 0.5, 42.0];
/// position[Axis::Y] *= 4.0;
///
/// assert_eq!(position[Axis::Y], 2.0);
/// ```
///
/// `nalgebra` structures are also indexable using `Axis`.
/// For reference see [the documentation]
/// (http://nalgebra.org/doc/nalgebra/struct.Vector3.html#method.index).
///
/// ```
/// extern crate bvh;
/// extern crate nalgebra;
///
/// use bvh::axis::Axis;
/// use nalgebra::Point3;
///
/// # fn main() {
/// let mut position = Point3::new(1.0, 2.0, 3.0);
/// position[Axis::X] = 1000.0;
///
/// assert_eq!(position[Axis::X], 1000.0);
/// # }
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Axis {
    /// Index of the X axis.
    X = 0,

    /// Index of the Y axis.
    Y = 1,

    /// Index of the Z axis.
    Z = 2,
}

/// Display implementation for `Axis`.
impl Display for Axis {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let c = match *self {
            Axis::X => "x",
            Axis::Y => "y",
            Axis::Z => "z",
        };
        write!(f, "{}", c)
    }
}

/// Make slices indexable by `Axis`.
impl Index<Axis> for [f32] {
    type Output = f32;

    fn index(&self, axis: Axis) -> &f32 {
        &self[axis as usize]
    }
}

/// Make slices mutably accessible by `Axis`.
impl IndexMut<Axis> for [f32] {
    fn index_mut(&mut self, axis: Axis) -> &mut f32 {
        &mut self[axis as usize]
    }
}

#[cfg(test)]
mod test {
    use axis::Axis;

    /// Test whether accessing arrays by index is the same as accessing them by `Axis`.
    quickcheck!{
        fn test_index_by_axis(tpl: (f32, f32, f32)) -> bool {
            let a = [tpl.0, tpl.1, tpl.2];

            a[0] == a[Axis::X] && a[1] == a[Axis::Y] && a[2] == a[Axis::Z]
        }
    }

    /// Test whether arrays can be mutably set, by indexing via `Axis`.
    quickcheck!{
        fn test_set_by_axis(tpl: (f32, f32, f32)) -> bool {
            let mut a = [0.0, 0.0, 0.0];

            a[Axis::X] = tpl.0;
            a[Axis::Y] = tpl.1;
            a[Axis::Z] = tpl.2;

            a[0] == tpl.0 && a[1] == tpl.1 && a[2] == tpl.2
        }
    }
}
<|endoftext|>


<commit_before>//! Streaming bodies for Requests and Responses
use std::borrow::Cow;
use std::fmt;

use bytes::Bytes;
use futures::{Async, Future, Poll, Stream};
use futures::sync::{mpsc, oneshot};
use h2;
use http::HeaderMap;

use common::Never;
use super::Chunk;

type BodySender = mpsc::Sender<Result<Chunk, ::Error>>;

/// This trait represents a streaming body of a `Request` or `Response`.
pub trait Payload: Send + 'static {
    /// A buffer of bytes representing a single chunk of a body.
    type Data: AsRef<[u8]> + Send;

    /// The error type of this stream.
    type Error: Into<Box<::std::error::Error + Send + Sync>>;

    /// Poll for a `Data` buffer.
    ///
    /// Similar to `Stream::poll_next`, this yields `Some(Data)` until
    /// the body ends, when it yields `None`.
    fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error>;

    /// Poll for an optional **single** `HeaderMap` of trailers.
    ///
    /// This should **only** be called after `poll_data` has ended.
    ///
    /// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2.
    fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> {
        Ok(Async::Ready(None))
    }

    /// A hint that the `Body` is complete, and doesn't need to be polled more.
    ///
    /// This can be useful to determine if the there is any body or trailers
    /// without having to poll. An empty `Body` could return `true` and hyper
    /// would be able to know that only the headers need to be sent. Or, it can
    /// also be checked after each `poll_data` call, to allow hyper to try to
    /// end the underlying stream with the last chunk, instead of needing to
    /// send an extra `DATA` frame just to mark the stream as finished.
    ///
    /// As a hint, it is used to try to optimize, and thus is OK for a default
    /// implementation to return `false`.
    fn is_end_stream(&self) -> bool {
        false
    }

    /// Return a length of the total bytes that will be streamed, if known.
    ///
    /// If an exact size of bytes is known, this would allow hyper to send a
    /// `Content-Length` header automatically, not needing to fall back to
    /// `Transfer-Encoding: chunked`.
    ///
    /// This does not need to be kept updated after polls, it will only be
    /// called once to create the headers.
    fn content_length(&self) -> Option<u64> {
        None
    }
}

impl<E: Payload> Payload for Box<E> {
    type Data = E::Data;
    type Error = E::Error;

    fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> {
        (**self).poll_data()
    }

    fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> {
        (**self).poll_trailers()
    }

    fn is_end_stream(&self) -> bool {
        (**self).is_end_stream()
    }

    fn content_length(&self) -> Option<u64> {
        (**self).content_length()
    }
}

/// A `Payload` of `Chunk`s, used when receiving bodies.
///
/// Also a good default `Payload` to use in many applications.
#[must_use = "streams do nothing unless polled"]
pub struct Body {
    kind: Kind,
    /// Allow the client to pass a future to delay the `Body` from returning
    /// EOF. This allows the `Client` to try to put the idle connection
    /// back into the pool before the body is "finished".
    ///
    /// The reason for this is so that creating a new request after finishing
    /// streaming the body of a response could sometimes result in creating
    /// a brand new connection, since the pool didn't know about the idle
    /// connection yet.
    delayed_eof: Option<DelayEof>,
}

enum Kind {
    Chan {
        _close_tx: oneshot::Sender<()>,
        rx: mpsc::Receiver<Result<Chunk, ::Error>>,
    },
    H2(h2::RecvStream),
    Wrapped(Box<Stream<Item=Chunk, Error=Box<::std::error::Error + Send + Sync>> + Send>),
    Once(Option<Chunk>),
    Empty,
}

type DelayEofUntil = oneshot::Receiver<Never>;

enum DelayEof {
    /// Initial state, stream hasn't seen EOF yet.
    NotEof(DelayEofUntil),
    /// Transitions to this state once we've seen `poll` try to
    /// return EOF (`None`). This future is then polled, and
    /// when it completes, the Body finally returns EOF (`None`).
    Eof(DelayEofUntil),
}

/// A sender half used with `Body::channel()`.
#[derive(Debug)]
pub struct Sender {
    close_rx: oneshot::Receiver<()>,
    tx: BodySender,
}

impl Body {
    /// Create an empty `Body` stream.
    ///
    /// # Example
    ///
    /// ```
    /// use hyper::{Body, Request};
    ///
    /// // create a `GET /` request
    /// let get = Request::new(Body::empty());
    /// ```
    #[inline]
    pub fn empty() -> Body {
        Body::new(Kind::Empty)
    }

    /// Create a `Body` stream with an associated sender half.
    #[inline]
    pub fn channel() -> (Sender, Body) {
        let (tx, rx) = mpsc::channel(0);
        let (close_tx, close_rx) = oneshot::channel();

        let tx = Sender {
            close_rx: close_rx,
            tx: tx,
        };
        let rx = Body::new(Kind::Chan {
            _close_tx: close_tx,
            rx: rx,
        });

        (tx, rx)
    }

    /// Wrap a futures `Stream` in a box inside `Body`.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate futures;
    /// # extern crate hyper;
    /// # use hyper::Body;
    /// # fn main() {
    /// let chunks = vec![
    ///     "hello",
    ///     " ",
    ///     "world",
    /// ];
    ///
    /// let stream = futures::stream::iter_ok::<_, ::std::io::Error>(chunks);
    ///
    /// let body = Body::wrap_stream(stream);
    /// # }
    /// ```
    pub fn wrap_stream<S>(stream: S) -> Body
    where
        S: Stream + Send + 'static,
        S::Error: Into<Box<::std::error::Error + Send + Sync>>,
        Chunk: From<S::Item>,
    {
        let mapped = stream
            .map(Chunk::from)
            .map_err(Into::into);
        Body::new(Kind::Wrapped(Box::new(mapped)))
    }

    /// Returns if this body was constructed via `Body::empty()`.
    ///
    /// # Note
    ///
    /// This does **not** detect if the body stream may be at the end, or
    /// if the stream will not yield any chunks, in all cases. For instance,
    /// a streaming body using `chunked` encoding is not able to tell if
    /// there are more chunks immediately.
    #[inline]
    pub fn is_empty(&self) -> bool {
        match self.kind {
            Kind::Empty => true,
            _ => false,
        }
    }

    fn new(kind: Kind) -> Body {
        Body {
            kind: kind,
            delayed_eof: None,
        }
    }

    pub(crate) fn h2(recv: h2::RecvStream) -> Self {
        Body::new(Kind::H2(recv))
    }

    pub(crate) fn delayed_eof(&mut self, fut: DelayEofUntil) {
        self.delayed_eof = Some(DelayEof::NotEof(fut));
    }

    fn poll_eof(&mut self) -> Poll<Option<Chunk>, ::Error> {
        match self.delayed_eof.take() {
            Some(DelayEof::NotEof(mut delay)) => {
                match self.poll_inner() {
                    ok @ Ok(Async::Ready(Some(..))) |
                    ok @ Ok(Async::NotReady) => {
                        self.delayed_eof = Some(DelayEof::NotEof(delay));
                        ok
                    },
                    Ok(Async::Ready(None)) => match delay.poll() {
                        Ok(Async::Ready(never)) => match never {},
                        Ok(Async::NotReady) => {
                            self.delayed_eof = Some(DelayEof::Eof(delay));
                            Ok(Async::NotReady)
                        },
                        Err(_done) => {
                            Ok(Async::Ready(None))
                        },
                    },
                    Err(e) => Err(e),
                }
            },
            Some(DelayEof::Eof(mut delay)) => {
                match delay.poll() {
                    Ok(Async::Ready(never)) => match never {},
                    Ok(Async::NotReady) => {
                        self.delayed_eof = Some(DelayEof::Eof(delay));
                        Ok(Async::NotReady)
                    },
                    Err(_done) => {
                        Ok(Async::Ready(None))
                    },
                }
            },
            None => self.poll_inner(),
        }
    }

    fn poll_inner(&mut self) -> Poll<Option<Chunk>, ::Error> {
        match self.kind {
            Kind::Chan { ref mut rx, .. } => match rx.poll().expect("mpsc cannot error") {
                Async::Ready(Some(Ok(chunk))) => Ok(Async::Ready(Some(chunk))),
                Async::Ready(Some(Err(err))) => Err(err),
                Async::Ready(None) => Ok(Async::Ready(None)),
                Async::NotReady => Ok(Async::NotReady),
            },
            Kind::H2(ref mut h2) => {
                h2.poll()
                    .map(|async| {
                        async.map(|opt| {
                            opt.map(|bytes| {
                                Chunk::h2(bytes, h2.release_capacity())
                            })
                        })
                    })
                    .map_err(::Error::new_body)
            },
            Kind::Wrapped(ref mut s) => s.poll().map_err(::Error::new_body),
            Kind::Once(ref mut val) => Ok(Async::Ready(val.take())),
            Kind::Empty => Ok(Async::Ready(None)),
        }
    }
}

impl Default for Body {
    #[inline]
    fn default() -> Body {
        Body::empty()
    }
}

impl Payload for Body {
    type Data = Chunk;
    type Error = ::Error;

    fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> {
        self.poll_eof()
    }

    fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> {
        match self.kind {
            Kind::H2(ref mut h2) => h2.poll_trailers().map_err(::Error::new_h2),
            _ => Ok(Async::Ready(None)),
        }
    }

    fn is_end_stream(&self) -> bool {
        match self.kind {
            Kind::Chan { .. } => false,
            Kind::H2(..) => false,
            Kind::Wrapped(..) => false,
            Kind::Once(ref val) => val.is_none(),
            Kind::Empty => true
        }
    }

    fn content_length(&self) -> Option<u64> {
        match self.kind {
            Kind::Chan { .. } => None,
            Kind::H2(..) => None,
            Kind::Wrapped(..) => None,
            Kind::Once(Some(ref val)) => Some(val.len() as u64),
            Kind::Once(None) => None,
            Kind::Empty => Some(0)
        }
    }
}

impl Stream for Body {
    type Item = Chunk;
    type Error = ::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.poll_data()
    }
}

impl fmt::Debug for Body {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Body")
            .finish()
    }
}

impl Sender {
    /// Check to see if this `Sender` can send more data.
    pub fn poll_ready(&mut self) -> Poll<(), ()> {
        match self.close_rx.poll() {
            Ok(Async::Ready(())) | Err(_) => return Err(()),
            Ok(Async::NotReady) => (),
        }

        self.tx.poll_ready().map_err(|_| ())
    }

    /// Sends data on this channel.
    ///
    /// This should be called after `poll_ready` indicated the channel
    /// could accept another `Chunk`.
    ///
    /// Returns `Err(Chunk)` if the channel could not (currently) accept
    /// another `Chunk`.
    pub fn send_data(&mut self, chunk: Chunk) -> Result<(), Chunk> {
        self.tx.try_send(Ok(chunk))
            .map_err(|err| err.into_inner().expect("just sent Ok"))
    }

    pub(crate) fn send_error(&mut self, err: ::Error) {
        let _ = self.tx.try_send(Err(err));
    }
}

impl From<Chunk> for Body {
    #[inline]
    fn from(chunk: Chunk) -> Body {
        if chunk.is_empty() {
            Body::empty()
        } else {
            Body::new(Kind::Once(Some(chunk)))
        }
    }
}

impl From<Bytes> for Body {
    #[inline]
    fn from (bytes: Bytes) -> Body {
        Body::from(Chunk::from(bytes))
    }
}

impl From<Vec<u8>> for Body {
    #[inline]
    fn from (vec: Vec<u8>) -> Body {
        Body::from(Chunk::from(vec))
    }
}

impl From<&'static [u8]> for Body {
    #[inline]
    fn from (slice: &'static [u8]) -> Body {
        Body::from(Chunk::from(slice))
    }
}

impl From<Cow<'static, [u8]>> for Body {
    #[inline]
    fn from (cow: Cow<'static, [u8]>) -> Body {
        match cow {
            Cow::Borrowed(b) => Body::from(b),
            Cow::Owned(o) => Body::from(o)
        }
    }
}

impl From<String> for Body {
    #[inline]
    fn from (s: String) -> Body {
        Body::from(Chunk::from(s.into_bytes()))
    }
}

impl From<&'static str> for Body {
    #[inline]
    fn from(slice: &'static str) -> Body {
        Body::from(Chunk::from(slice.as_bytes()))
    }
}

impl From<Cow<'static, str>> for Body {
    #[inline]
    fn from(cow: Cow<'static, str>) -> Body {
        match cow {
            Cow::Borrowed(b) => Body::from(b),
            Cow::Owned(o) => Body::from(o)
        }
    }
}

fn _assert_send_sync() {
    fn _assert_send<T: Send>() {}
    fn _assert_sync<T: Sync>() {}

    _assert_send::<Body>();
    _assert_send::<Chunk>();
    _assert_sync::<Chunk>();
}

#[test]
fn test_body_stream_concat() {
    use futures::{Stream, Future};

    let body = Body::from("hello world");

    let total = body
        .concat2()
        .wait()
        .unwrap();
    assert_eq!(total.as_ref(), b"hello world");
}

<commit_msg>perf(http2): improve Body::is_end_stream detection for http2<commit_after>//! Streaming bodies for Requests and Responses
use std::borrow::Cow;
use std::fmt;

use bytes::Bytes;
use futures::{Async, Future, Poll, Stream};
use futures::sync::{mpsc, oneshot};
use h2;
use http::HeaderMap;

use common::Never;
use super::Chunk;

type BodySender = mpsc::Sender<Result<Chunk, ::Error>>;

/// This trait represents a streaming body of a `Request` or `Response`.
pub trait Payload: Send + 'static {
    /// A buffer of bytes representing a single chunk of a body.
    type Data: AsRef<[u8]> + Send;

    /// The error type of this stream.
    type Error: Into<Box<::std::error::Error + Send + Sync>>;

    /// Poll for a `Data` buffer.
    ///
    /// Similar to `Stream::poll_next`, this yields `Some(Data)` until
    /// the body ends, when it yields `None`.
    fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error>;

    /// Poll for an optional **single** `HeaderMap` of trailers.
    ///
    /// This should **only** be called after `poll_data` has ended.
    ///
    /// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2.
    fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> {
        Ok(Async::Ready(None))
    }

    /// A hint that the `Body` is complete, and doesn't need to be polled more.
    ///
    /// This can be useful to determine if the there is any body or trailers
    /// without having to poll. An empty `Body` could return `true` and hyper
    /// would be able to know that only the headers need to be sent. Or, it can
    /// also be checked after each `poll_data` call, to allow hyper to try to
    /// end the underlying stream with the last chunk, instead of needing to
    /// send an extra `DATA` frame just to mark the stream as finished.
    ///
    /// As a hint, it is used to try to optimize, and thus is OK for a default
    /// implementation to return `false`.
    fn is_end_stream(&self) -> bool {
        false
    }

    /// Return a length of the total bytes that will be streamed, if known.
    ///
    /// If an exact size of bytes is known, this would allow hyper to send a
    /// `Content-Length` header automatically, not needing to fall back to
    /// `Transfer-Encoding: chunked`.
    ///
    /// This does not need to be kept updated after polls, it will only be
    /// called once to create the headers.
    fn content_length(&self) -> Option<u64> {
        None
    }
}

impl<E: Payload> Payload for Box<E> {
    type Data = E::Data;
    type Error = E::Error;

    fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> {
        (**self).poll_data()
    }

    fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> {
        (**self).poll_trailers()
    }

    fn is_end_stream(&self) -> bool {
        (**self).is_end_stream()
    }

    fn content_length(&self) -> Option<u64> {
        (**self).content_length()
    }
}

/// A `Payload` of `Chunk`s, used when receiving bodies.
///
/// Also a good default `Payload` to use in many applications.
#[must_use = "streams do nothing unless polled"]
pub struct Body {
    kind: Kind,
    /// Allow the client to pass a future to delay the `Body` from returning
    /// EOF. This allows the `Client` to try to put the idle connection
    /// back into the pool before the body is "finished".
    ///
    /// The reason for this is so that creating a new request after finishing
    /// streaming the body of a response could sometimes result in creating
    /// a brand new connection, since the pool didn't know about the idle
    /// connection yet.
    delayed_eof: Option<DelayEof>,
}

enum Kind {
    Chan {
        _close_tx: oneshot::Sender<()>,
        rx: mpsc::Receiver<Result<Chunk, ::Error>>,
    },
    H2(h2::RecvStream),
    Wrapped(Box<Stream<Item=Chunk, Error=Box<::std::error::Error + Send + Sync>> + Send>),
    Once(Option<Chunk>),
    Empty,
}

type DelayEofUntil = oneshot::Receiver<Never>;

enum DelayEof {
    /// Initial state, stream hasn't seen EOF yet.
    NotEof(DelayEofUntil),
    /// Transitions to this state once we've seen `poll` try to
    /// return EOF (`None`). This future is then polled, and
    /// when it completes, the Body finally returns EOF (`None`).
    Eof(DelayEofUntil),
}

/// A sender half used with `Body::channel()`.
#[derive(Debug)]
pub struct Sender {
    close_rx: oneshot::Receiver<()>,
    tx: BodySender,
}

impl Body {
    /// Create an empty `Body` stream.
    ///
    /// # Example
    ///
    /// ```
    /// use hyper::{Body, Request};
    ///
    /// // create a `GET /` request
    /// let get = Request::new(Body::empty());
    /// ```
    #[inline]
    pub fn empty() -> Body {
        Body::new(Kind::Empty)
    }

    /// Create a `Body` stream with an associated sender half.
    #[inline]
    pub fn channel() -> (Sender, Body) {
        let (tx, rx) = mpsc::channel(0);
        let (close_tx, close_rx) = oneshot::channel();

        let tx = Sender {
            close_rx: close_rx,
            tx: tx,
        };
        let rx = Body::new(Kind::Chan {
            _close_tx: close_tx,
            rx: rx,
        });

        (tx, rx)
    }

    /// Wrap a futures `Stream` in a box inside `Body`.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate futures;
    /// # extern crate hyper;
    /// # use hyper::Body;
    /// # fn main() {
    /// let chunks = vec![
    ///     "hello",
    ///     " ",
    ///     "world",
    /// ];
    ///
    /// let stream = futures::stream::iter_ok::<_, ::std::io::Error>(chunks);
    ///
    /// let body = Body::wrap_stream(stream);
    /// # }
    /// ```
    pub fn wrap_stream<S>(stream: S) -> Body
    where
        S: Stream + Send + 'static,
        S::Error: Into<Box<::std::error::Error + Send + Sync>>,
        Chunk: From<S::Item>,
    {
        let mapped = stream
            .map(Chunk::from)
            .map_err(Into::into);
        Body::new(Kind::Wrapped(Box::new(mapped)))
    }

    /// Returns if this body was constructed via `Body::empty()`.
    ///
    /// # Note
    ///
    /// This does **not** detect if the body stream may be at the end, or
    /// if the stream will not yield any chunks, in all cases. For instance,
    /// a streaming body using `chunked` encoding is not able to tell if
    /// there are more chunks immediately.
    #[inline]
    pub fn is_empty(&self) -> bool {
        match self.kind {
            Kind::Empty => true,
            _ => false,
        }
    }

    fn new(kind: Kind) -> Body {
        Body {
            kind: kind,
            delayed_eof: None,
        }
    }

    pub(crate) fn h2(recv: h2::RecvStream) -> Self {
        Body::new(Kind::H2(recv))
    }

    pub(crate) fn delayed_eof(&mut self, fut: DelayEofUntil) {
        self.delayed_eof = Some(DelayEof::NotEof(fut));
    }

    fn poll_eof(&mut self) -> Poll<Option<Chunk>, ::Error> {
        match self.delayed_eof.take() {
            Some(DelayEof::NotEof(mut delay)) => {
                match self.poll_inner() {
                    ok @ Ok(Async::Ready(Some(..))) |
                    ok @ Ok(Async::NotReady) => {
                        self.delayed_eof = Some(DelayEof::NotEof(delay));
                        ok
                    },
                    Ok(Async::Ready(None)) => match delay.poll() {
                        Ok(Async::Ready(never)) => match never {},
                        Ok(Async::NotReady) => {
                            self.delayed_eof = Some(DelayEof::Eof(delay));
                            Ok(Async::NotReady)
                        },
                        Err(_done) => {
                            Ok(Async::Ready(None))
                        },
                    },
                    Err(e) => Err(e),
                }
            },
            Some(DelayEof::Eof(mut delay)) => {
                match delay.poll() {
                    Ok(Async::Ready(never)) => match never {},
                    Ok(Async::NotReady) => {
                        self.delayed_eof = Some(DelayEof::Eof(delay));
                        Ok(Async::NotReady)
                    },
                    Err(_done) => {
                        Ok(Async::Ready(None))
                    },
                }
            },
            None => self.poll_inner(),
        }
    }

    fn poll_inner(&mut self) -> Poll<Option<Chunk>, ::Error> {
        match self.kind {
            Kind::Chan { ref mut rx, .. } => match rx.poll().expect("mpsc cannot error") {
                Async::Ready(Some(Ok(chunk))) => Ok(Async::Ready(Some(chunk))),
                Async::Ready(Some(Err(err))) => Err(err),
                Async::Ready(None) => Ok(Async::Ready(None)),
                Async::NotReady => Ok(Async::NotReady),
            },
            Kind::H2(ref mut h2) => {
                h2.poll()
                    .map(|async| {
                        async.map(|opt| {
                            opt.map(|bytes| {
                                Chunk::h2(bytes, h2.release_capacity())
                            })
                        })
                    })
                    .map_err(::Error::new_body)
            },
            Kind::Wrapped(ref mut s) => s.poll().map_err(::Error::new_body),
            Kind::Once(ref mut val) => Ok(Async::Ready(val.take())),
            Kind::Empty => Ok(Async::Ready(None)),
        }
    }
}

impl Default for Body {
    #[inline]
    fn default() -> Body {
        Body::empty()
    }
}

impl Payload for Body {
    type Data = Chunk;
    type Error = ::Error;

    fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> {
        self.poll_eof()
    }

    fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> {
        match self.kind {
            Kind::H2(ref mut h2) => h2.poll_trailers().map_err(::Error::new_h2),
            _ => Ok(Async::Ready(None)),
        }
    }

    fn is_end_stream(&self) -> bool {
        match self.kind {
            Kind::Chan { .. } => false,
            Kind::H2(ref h2) => h2.is_end_stream(),
            Kind::Wrapped(..) => false,
            Kind::Once(ref val) => val.is_none(),
            Kind::Empty => true
        }
    }

    fn content_length(&self) -> Option<u64> {
        match self.kind {
            Kind::Chan { .. } => None,
            Kind::H2(..) => None,
            Kind::Wrapped(..) => None,
            Kind::Once(Some(ref val)) => Some(val.len() as u64),
            Kind::Once(None) => None,
            Kind::Empty => Some(0)
        }
    }
}

impl Stream for Body {
    type Item = Chunk;
    type Error = ::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.poll_data()
    }
}

impl fmt::Debug for Body {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Body")
            .finish()
    }
}

impl Sender {
    /// Check to see if this `Sender` can send more data.
    pub fn poll_ready(&mut self) -> Poll<(), ()> {
        match self.close_rx.poll() {
            Ok(Async::Ready(())) | Err(_) => return Err(()),
            Ok(Async::NotReady) => (),
        }

        self.tx.poll_ready().map_err(|_| ())
    }

    /// Sends data on this channel.
    ///
    /// This should be called after `poll_ready` indicated the channel
    /// could accept another `Chunk`.
    ///
    /// Returns `Err(Chunk)` if the channel could not (currently) accept
    /// another `Chunk`.
    pub fn send_data(&mut self, chunk: Chunk) -> Result<(), Chunk> {
        self.tx.try_send(Ok(chunk))
            .map_err(|err| err.into_inner().expect("just sent Ok"))
    }

    pub(crate) fn send_error(&mut self, err: ::Error) {
        let _ = self.tx.try_send(Err(err));
    }
}

impl From<Chunk> for Body {
    #[inline]
    fn from(chunk: Chunk) -> Body {
        if chunk.is_empty() {
            Body::empty()
        } else {
            Body::new(Kind::Once(Some(chunk)))
        }
    }
}

impl From<Bytes> for Body {
    #[inline]
    fn from (bytes: Bytes) -> Body {
        Body::from(Chunk::from(bytes))
    }
}

impl From<Vec<u8>> for Body {
    #[inline]
    fn from (vec: Vec<u8>) -> Body {
        Body::from(Chunk::from(vec))
    }
}

impl From<&'static [u8]> for Body {
    #[inline]
    fn from (slice: &'static [u8]) -> Body {
        Body::from(Chunk::from(slice))
    }
}

impl From<Cow<'static, [u8]>> for Body {
    #[inline]
    fn from (cow: Cow<'static, [u8]>) -> Body {
        match cow {
            Cow::Borrowed(b) => Body::from(b),
            Cow::Owned(o) => Body::from(o)
        }
    }
}

impl From<String> for Body {
    #[inline]
    fn from (s: String) -> Body {
        Body::from(Chunk::from(s.into_bytes()))
    }
}

impl From<&'static str> for Body {
    #[inline]
    fn from(slice: &'static str) -> Body {
        Body::from(Chunk::from(slice.as_bytes()))
    }
}

impl From<Cow<'static, str>> for Body {
    #[inline]
    fn from(cow: Cow<'static, str>) -> Body {
        match cow {
            Cow::Borrowed(b) => Body::from(b),
            Cow::Owned(o) => Body::from(o)
        }
    }
}

fn _assert_send_sync() {
    fn _assert_send<T: Send>() {}
    fn _assert_sync<T: Sync>() {}

    _assert_send::<Body>();
    _assert_send::<Chunk>();
    _assert_sync::<Chunk>();
}

#[test]
fn test_body_stream_concat() {
    use futures::{Stream, Future};

    let body = Body::from("hello world");

    let total = body
        .concat2()
        .wait()
        .unwrap();
    assert_eq!(total.as_ref(), b"hello world");
}

<|endoftext|>


<commit_before>//! Conditional processing attributes: `requiredExtensions`, `requiredFeatures`, `systemLanguage`.

#[allow(unused_imports, deprecated)]
use std::ascii::AsciiExt;

use std::str::FromStr;

use language_tags::LanguageTag;
use locale_config::{LanguageRange, Locale};

use crate::error::*;

// No extensions at the moment.
static IMPLEMENTED_EXTENSIONS: &[&str] = &[];

#[derive(Debug, PartialEq)]
pub struct RequiredExtensions(pub bool);

impl RequiredExtensions {
    /// Parse a requiredExtensions attribute.
    ///
    /// http://www.w3.org/TR/SVG/struct.html#RequiredExtensionsAttribute
    pub fn from_attribute(s: &str) -> Result<RequiredExtensions, ValueErrorKind> {
        Ok(RequiredExtensions(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_EXTENSIONS.binary_search(&f).is_ok()),
        ))
    }

    /// Evaluate a requiredExtensions value for conditional processing.
    pub fn eval(&self) -> bool {
        self.0
    }
}

// Keep these sorted alphabetically for binary_search.
static IMPLEMENTED_FEATURES: &[&str] = &[
    "http://www.w3.org/TR/SVG11/feature#BasicFilter",
    "http://www.w3.org/TR/SVG11/feature#BasicGraphicsAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicPaintAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicStructure",
    "http://www.w3.org/TR/SVG11/feature#BasicText",
    "http://www.w3.org/TR/SVG11/feature#ConditionalProcessing",
    "http://www.w3.org/TR/SVG11/feature#ContainerAttribute",
    "http://www.w3.org/TR/SVG11/feature#Filter",
    "http://www.w3.org/TR/SVG11/feature#Gradient",
    "http://www.w3.org/TR/SVG11/feature#Image",
    "http://www.w3.org/TR/SVG11/feature#Marker",
    "http://www.w3.org/TR/SVG11/feature#Mask",
    "http://www.w3.org/TR/SVG11/feature#OpacityAttribute",
    "http://www.w3.org/TR/SVG11/feature#Pattern",
    "http://www.w3.org/TR/SVG11/feature#SVG",
    "http://www.w3.org/TR/SVG11/feature#SVG-static",
    "http://www.w3.org/TR/SVG11/feature#Shape",
    "http://www.w3.org/TR/SVG11/feature#Structure",
    "http://www.w3.org/TR/SVG11/feature#Style",
    "http://www.w3.org/TR/SVG11/feature#View",
    "org.w3c.svg.static", // deprecated SVG 1.0 feature string
];

#[derive(Debug, PartialEq)]
pub struct RequiredFeatures(pub bool);

impl RequiredFeatures {
    // Parse a requiredFeatures attribute
    // http://www.w3.org/TR/SVG/struct.html#RequiredFeaturesAttribute
    pub fn from_attribute(s: &str) -> Result<RequiredFeatures, ValueErrorKind> {
        Ok(RequiredFeatures(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_FEATURES.binary_search(&f).is_ok()),
        ))
    }

    /// Evaluate a requiredFeatures value for conditional processing.
    pub fn eval(&self) -> bool {
        self.0
    }
}

/// A list of BCP47 language tags.
///
/// https://www.rfc-editor.org/info/rfc5664
#[derive(Debug, Clone, PartialEq)]
pub struct LanguageTags(Vec<LanguageTag>);

impl LanguageTags {
    pub fn empty() -> Self {
        LanguageTags(Vec::new())
    }

    /// Converts a `Locale` to a set of language tags.
    pub fn from_locale(locale: &Locale) -> Result<LanguageTags, String> {
        let mut tags = Vec::new();

        for locale_range in locale.tags_for("messages") {
            if locale_range == LanguageRange::invariant() {
                continue;
            }

            let str_locale_range = locale_range.as_ref();

            let locale_tag = LanguageTag::from_str(str_locale_range).map_err(|e| {
                format!(
                    "invalid language tag \"{}\" in locale: {}",
                    str_locale_range, e
                )
            })?;

            if !locale_tag.is_language_range() {
                return Err(format!(
                    "language tag \"{}\" is not a language range",
                    locale_tag
                ));
            }

            tags.push(locale_tag);
        }

        Ok(LanguageTags(tags))
    }

    pub fn iter(&self) -> impl Iterator<Item = &LanguageTag> {
        self.0.iter()
    }

    fn any_matches(&self, language_tag: &LanguageTag) -> bool {
        self.0.iter().any(|tag| tag.matches(language_tag))
    }
}

#[derive(Debug, PartialEq)]
pub struct SystemLanguage(LanguageTags);

impl SystemLanguage {
    /// Parse a `systemLanguage` attribute and match it against a given `Locale`
    ///
    /// The [`systemLanguage`] conditional attribute is a
    /// comma-separated list of [BCP47] Language Tags.  This function
    /// parses the attribute and matches the result against a given
    /// `locale`.  If there is a match, i.e. if the given locale
    /// supports one of the languages listed in the `systemLanguage`
    /// attribute, then the `SystemLanguage.0` will be `true`;
    /// otherwise it will be `false`.
    ///
    /// Normally, calling code will pass `&Locale::current()` for the
    /// `locale` attribute; this is the user's current locale.
    ///
    /// [`systemLanguage`]: https://www.w3.org/TR/SVG/struct.html#ConditionalProcessingSystemLanguageAttribute
    /// [BCP47]: http://www.ietf.org/rfc/bcp/bcp47.txt
    pub fn from_attribute(s: &str) -> Result<SystemLanguage, ValueErrorKind> {
        let attribute_tags = s
            .split(',')
            .map(str::trim)
            .map(|s| {
                LanguageTag::from_str(s).map_err(|e| {
                    ValueErrorKind::parse_error(&format!("invalid language tag: \"{}\"", e))
                })
            })
            .collect::<Result<Vec<LanguageTag>, _>>()?;

        Ok(SystemLanguage(LanguageTags(attribute_tags)))
    }

    /// Evaluate a systemLanguage value for conditional processing.
    pub fn eval(&self, locale_tags: &LanguageTags) -> bool {
        self.0.iter().any(|tag| locale_tags.any_matches(tag))
    }
}

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

    #[test]
    fn required_extensions() {
        assert_eq!(
            RequiredExtensions::from_attribute("http://test.org/NotExisting/1.0").unwrap(),
            RequiredExtensions(false)
        );
    }

    #[test]
    fn required_features() {
        assert_eq!(
            RequiredFeatures::from_attribute("http://www.w3.org/TR/SVG11/feature#NotExisting")
                .unwrap(),
            RequiredFeatures(false)
        );

        assert_eq!(
            RequiredFeatures::from_attribute("http://www.w3.org/TR/SVG11/feature#BasicFilter")
                .unwrap(),
            RequiredFeatures(true)
        );

        assert_eq!(
            RequiredFeatures::from_attribute(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#NotExisting",
            )
            .unwrap(),
            RequiredFeatures(false)
        );

        assert_eq!(
            RequiredFeatures::from_attribute(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#BasicText",
            )
            .unwrap(),
            RequiredFeatures(true)
        );
    }

    #[test]
    fn system_language() {
        let locale = Locale::new("de,en-US").unwrap();

        let locale_tags = LanguageTags::from_locale(&locale).unwrap();

        assert!(SystemLanguage::from_attribute("").is_err());

        assert!(SystemLanguage::from_attribute("12345").is_err());

        assert_eq!(
            SystemLanguage::from_attribute("fr")
                .unwrap()
                .eval(&locale_tags),
            false
        );

        assert_eq!(
            SystemLanguage::from_attribute("en")
                .unwrap()
                .eval(&locale_tags),
            false
        );

        assert_eq!(
            SystemLanguage::from_attribute("de")
                .unwrap()
                .eval(&locale_tags),
            true
        );

        assert_eq!(
            SystemLanguage::from_attribute("en-US")
                .unwrap()
                .eval(&locale_tags),
            true
        );

        assert_eq!(
            SystemLanguage::from_attribute("en-GB")
                .unwrap()
                .eval(&locale_tags),
            false
        );

        assert_eq!(
            SystemLanguage::from_attribute("DE")
                .unwrap()
                .eval(&locale_tags),
            true
        );

        assert_eq!(
            SystemLanguage::from_attribute("de-LU")
                .unwrap()
                .eval(&locale_tags),
            true
        );

        assert_eq!(
            SystemLanguage::from_attribute("fr, de")
                .unwrap()
                .eval(&locale_tags),
            true
        );
    }
}
<commit_msg>Add LanguagetTags::from() to construct it from a vector<commit_after>//! Conditional processing attributes: `requiredExtensions`, `requiredFeatures`, `systemLanguage`.

#[allow(unused_imports, deprecated)]
use std::ascii::AsciiExt;

use std::str::FromStr;

use language_tags::LanguageTag;
use locale_config::{LanguageRange, Locale};

use crate::error::*;

// No extensions at the moment.
static IMPLEMENTED_EXTENSIONS: &[&str] = &[];

#[derive(Debug, PartialEq)]
pub struct RequiredExtensions(pub bool);

impl RequiredExtensions {
    /// Parse a requiredExtensions attribute.
    ///
    /// http://www.w3.org/TR/SVG/struct.html#RequiredExtensionsAttribute
    pub fn from_attribute(s: &str) -> Result<RequiredExtensions, ValueErrorKind> {
        Ok(RequiredExtensions(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_EXTENSIONS.binary_search(&f).is_ok()),
        ))
    }

    /// Evaluate a requiredExtensions value for conditional processing.
    pub fn eval(&self) -> bool {
        self.0
    }
}

// Keep these sorted alphabetically for binary_search.
static IMPLEMENTED_FEATURES: &[&str] = &[
    "http://www.w3.org/TR/SVG11/feature#BasicFilter",
    "http://www.w3.org/TR/SVG11/feature#BasicGraphicsAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicPaintAttribute",
    "http://www.w3.org/TR/SVG11/feature#BasicStructure",
    "http://www.w3.org/TR/SVG11/feature#BasicText",
    "http://www.w3.org/TR/SVG11/feature#ConditionalProcessing",
    "http://www.w3.org/TR/SVG11/feature#ContainerAttribute",
    "http://www.w3.org/TR/SVG11/feature#Filter",
    "http://www.w3.org/TR/SVG11/feature#Gradient",
    "http://www.w3.org/TR/SVG11/feature#Image",
    "http://www.w3.org/TR/SVG11/feature#Marker",
    "http://www.w3.org/TR/SVG11/feature#Mask",
    "http://www.w3.org/TR/SVG11/feature#OpacityAttribute",
    "http://www.w3.org/TR/SVG11/feature#Pattern",
    "http://www.w3.org/TR/SVG11/feature#SVG",
    "http://www.w3.org/TR/SVG11/feature#SVG-static",
    "http://www.w3.org/TR/SVG11/feature#Shape",
    "http://www.w3.org/TR/SVG11/feature#Structure",
    "http://www.w3.org/TR/SVG11/feature#Style",
    "http://www.w3.org/TR/SVG11/feature#View",
    "org.w3c.svg.static", // deprecated SVG 1.0 feature string
];

#[derive(Debug, PartialEq)]
pub struct RequiredFeatures(pub bool);

impl RequiredFeatures {
    // Parse a requiredFeatures attribute
    // http://www.w3.org/TR/SVG/struct.html#RequiredFeaturesAttribute
    pub fn from_attribute(s: &str) -> Result<RequiredFeatures, ValueErrorKind> {
        Ok(RequiredFeatures(
            s.split_whitespace()
                .all(|f| IMPLEMENTED_FEATURES.binary_search(&f).is_ok()),
        ))
    }

    /// Evaluate a requiredFeatures value for conditional processing.
    pub fn eval(&self) -> bool {
        self.0
    }
}

/// A list of BCP47 language tags.
///
/// https://www.rfc-editor.org/info/rfc5664
#[derive(Debug, Clone, PartialEq)]
pub struct LanguageTags(Vec<LanguageTag>);

impl LanguageTags {
    pub fn empty() -> Self {
        LanguageTags(Vec::new())
    }

    /// Converts a `Locale` to a set of language tags.
    pub fn from_locale(locale: &Locale) -> Result<LanguageTags, String> {
        let mut tags = Vec::new();

        for locale_range in locale.tags_for("messages") {
            if locale_range == LanguageRange::invariant() {
                continue;
            }

            let str_locale_range = locale_range.as_ref();

            let locale_tag = LanguageTag::from_str(str_locale_range).map_err(|e| {
                format!(
                    "invalid language tag \"{}\" in locale: {}",
                    str_locale_range, e
                )
            })?;

            if !locale_tag.is_language_range() {
                return Err(format!(
                    "language tag \"{}\" is not a language range",
                    locale_tag
                ));
            }

            tags.push(locale_tag);
        }

        Ok(LanguageTags(tags))
    }

    pub fn from(tags: Vec<LanguageTag>) -> LanguageTags {
        LanguageTags(tags)
    }

    pub fn iter(&self) -> impl Iterator<Item = &LanguageTag> {
        self.0.iter()
    }

    fn any_matches(&self, language_tag: &LanguageTag) -> bool {
        self.0.iter().any(|tag| tag.matches(language_tag))
    }
}

#[derive(Debug, PartialEq)]
pub struct SystemLanguage(LanguageTags);

impl SystemLanguage {
    /// Parse a `systemLanguage` attribute and match it against a given `Locale`
    ///
    /// The [`systemLanguage`] conditional attribute is a
    /// comma-separated list of [BCP47] Language Tags.  This function
    /// parses the attribute and matches the result against a given
    /// `locale`.  If there is a match, i.e. if the given locale
    /// supports one of the languages listed in the `systemLanguage`
    /// attribute, then the `SystemLanguage.0` will be `true`;
    /// otherwise it will be `false`.
    ///
    /// Normally, calling code will pass `&Locale::current()` for the
    /// `locale` attribute; this is the user's current locale.
    ///
    /// [`systemLanguage`]: https://www.w3.org/TR/SVG/struct.html#ConditionalProcessingSystemLanguageAttribute
    /// [BCP47]: http://www.ietf.org/rfc/bcp/bcp47.txt
    pub fn from_attribute(s: &str) -> Result<SystemLanguage, ValueErrorKind> {
        let attribute_tags = s
            .split(',')
            .map(str::trim)
            .map(|s| {
                LanguageTag::from_str(s).map_err(|e| {
                    ValueErrorKind::parse_error(&format!("invalid language tag: \"{}\"", e))
                })
            })
            .collect::<Result<Vec<LanguageTag>, _>>()?;

        Ok(SystemLanguage(LanguageTags::from(attribute_tags)))
    }

    /// Evaluate a systemLanguage value for conditional processing.
    pub fn eval(&self, locale_tags: &LanguageTags) -> bool {
        self.0.iter().any(|tag| locale_tags.any_matches(tag))
    }
}

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

    #[test]
    fn required_extensions() {
        assert_eq!(
            RequiredExtensions::from_attribute("http://test.org/NotExisting/1.0").unwrap(),
            RequiredExtensions(false)
        );
    }

    #[test]
    fn required_features() {
        assert_eq!(
            RequiredFeatures::from_attribute("http://www.w3.org/TR/SVG11/feature#NotExisting")
                .unwrap(),
            RequiredFeatures(false)
        );

        assert_eq!(
            RequiredFeatures::from_attribute("http://www.w3.org/TR/SVG11/feature#BasicFilter")
                .unwrap(),
            RequiredFeatures(true)
        );

        assert_eq!(
            RequiredFeatures::from_attribute(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#NotExisting",
            )
            .unwrap(),
            RequiredFeatures(false)
        );

        assert_eq!(
            RequiredFeatures::from_attribute(
                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
                 http://www.w3.org/TR/SVG11/feature#BasicText",
            )
            .unwrap(),
            RequiredFeatures(true)
        );
    }

    #[test]
    fn system_language() {
        let locale = Locale::new("de,en-US").unwrap();

        let locale_tags = LanguageTags::from_locale(&locale).unwrap();

        assert!(SystemLanguage::from_attribute("").is_err());

        assert!(SystemLanguage::from_attribute("12345").is_err());

        assert_eq!(
            SystemLanguage::from_attribute("fr")
                .unwrap()
                .eval(&locale_tags),
            false
        );

        assert_eq!(
            SystemLanguage::from_attribute("en")
                .unwrap()
                .eval(&locale_tags),
            false
        );

        assert_eq!(
            SystemLanguage::from_attribute("de")
                .unwrap()
                .eval(&locale_tags),
            true
        );

        assert_eq!(
            SystemLanguage::from_attribute("en-US")
                .unwrap()
                .eval(&locale_tags),
            true
        );

        assert_eq!(
            SystemLanguage::from_attribute("en-GB")
                .unwrap()
                .eval(&locale_tags),
            false
        );

        assert_eq!(
            SystemLanguage::from_attribute("DE")
                .unwrap()
                .eval(&locale_tags),
            true
        );

        assert_eq!(
            SystemLanguage::from_attribute("de-LU")
                .unwrap()
                .eval(&locale_tags),
            true
        );

        assert_eq!(
            SystemLanguage::from_attribute("fr, de")
                .unwrap()
                .eval(&locale_tags),
            true
        );
    }
}
<|endoftext|>