<commit_before>//! Represent colors in HSL and convert between HSL and RGB.
//!
//! # Examples
//!
//! ```rust
//! use hsl::HSL;
//!
//! let yellow = [255, 255, 0];
//! let yellow_hsl = HSL::from_rgb(&yellow);
//!
//! assert_eq!(yellow_hsl, HSL { h: 60_f64, s: 1_f64, l: 0.5_f64 });
//! ```

/// Color represented in HSL
#[derive(Debug, PartialEq, PartialOrd, Default)]
pub struct HSL {
    /// Hue in 0-360 degree
    pub h: f64,
    /// Saturation in 0...1 (percent)
    pub s: f64,
    /// Luminosity in 0...1 (percent)
    pub l: f64,
}

impl HSL {
    /// Convert RGB pixel value to HSL
    ///
    /// Expects RGB pixel to be a slice of three `u8`s representing the red, green and blue values.
    ///
    /// ```rust
    /// use hsl::HSL;
    /// let blue = HSL::from_rgb(&[0, 0, 255]);
    /// ```
    ///
    /// Algorithm from [go-color] by Brandon Thomson <bt@brandonthomson.com>. (Iternally converts
    /// the pixel to RGB before converting it to HSL.)
    ///
    /// [go-color]: https://github.com/bthomson/go-color
    #[cfg_attr(feature = "dev", allow(float_cmp))]
    pub fn from_rgb(rgb: &[u8]) -> HSL {
        use std::cmp::{max, min};

        let mut h: f64;
        let s: f64;
        let l: f64;

        let (r, g, b) = (rgb[0], rgb[1], rgb[2]);

        let max = max(max(r, g), b);
        let min = min(min(r, g), b);

        // Normalized RGB: Divide everything by 255 to get percentages of colors.
        let (r, g, b) = (r as f64 / 255_f64, g as f64 / 255_f64, b as f64 / 255_f64);
        let (min, max) = (min as f64 / 255_f64, max as f64 / 255_f64);

        // Luminosity is the average of the max and min rgb color intensities.
        l = (max + min) / 2_f64;

        // Saturation
        let delta: f64 = max - min;
        if delta == 0_f64 {
    		// it's gray
            return HSL { h: 0_f64, s: 0_f64, l: l };
        }

        // it's not gray
        if l < 0.5_f64 {
            s = delta / (max + min);
        } else {
            s = delta / (2_f64 - max - min);
        }

        // Hue
        let r2 = (((max - r) / 6_f64) + (delta / 2_f64)) / delta;
        let g2 = (((max - g) / 6_f64) + (delta / 2_f64)) / delta;
        let b2 = (((max - b) / 6_f64) + (delta / 2_f64)) / delta;

        h = match max {
            x if x == r => b2 - g2,
            x if x == g => (1_f64 / 3_f64) + r2 - b2,
            _ => (2_f64 / 3_f64) + g2 - r2,
        };

        // Fix wraparounds
        if h < 0 as f64 {
            h += 1_f64;
        } else if h > 1 as f64 {
            h -= 1_f64;
        }

        // Hue is precise to milli-degrees, e.g. `74.52deg`.
        let h_degrees = (h * 360_f64 * 100_f64).round() / 100_f64;

        HSL { h: h_degrees, s: s, l: l }
    }

    /// Convert HSL color to RGB
    ///
    /// ```rust
    /// use hsl::HSL;
    ///
    /// let cyan = HSL { h: 180_f64, s: 1_f64, l: 0.5_f64 };
    /// assert_eq!(cyan.to_rgb(), (0, 255, 255));
    /// ```
    pub fn to_rgb(&self) -> (u8, u8, u8) {
        if self.s == 0.0 {
            // Achromatic, i.e., grey.
            let l = percent_to_byte(self.l);
            return (l, l, l);
        }

        let h = self.h / 360.0; // treat this as 0..1 instead of degrees
        let s = self.s;
        let l = self.l;

        let q = if l < 0.5 {
            l * (1.0 + s)
        } else {
            l + s - (l * s)
        };
        let p = 2.0 * l - q;

        (percent_to_byte(hue_to_rgb(p, q, h + 1.0 / 3.0)),
         percent_to_byte(hue_to_rgb(p, q, h)),
         percent_to_byte(hue_to_rgb(p, q, h - 1.0 / 3.0)))
    }
}

fn percent_to_byte(percent: f64) -> u8 {
    (percent * 255.0).round() as u8
}

/// Convert Hue to RGB Ratio
///
/// From <https://github.com/jariz/vibrant.js/> by Jari Zwarts
fn hue_to_rgb(p: f64, q: f64, t: f64) -> f64 {
    // Normalize
    let t = if t < 0.0 {
        t + 1.0
    } else if t > 1.0 {
        t - 1.0
    } else {
        t
    };

    if t < 1.0 / 6.0 {
        p + (q - p) * 6.0 * t
    } else if t < 1.0 / 2.0 {
        q
    } else if t < 2.0 / 3.0 {
        p + (q - p) * (2.0 / 3.0 - t) * 6.0
    } else {
        p
    }
}
<commit_msg>Rustfmt<commit_after>//! Represent colors in HSL and convert between HSL and RGB.
//!
//! # Examples
//!
//! ```rust
//! use hsl::HSL;
//!
//! let yellow = [255, 255, 0];
//! let yellow_hsl = HSL::from_rgb(&yellow);
//!
//! assert_eq!(yellow_hsl, HSL { h: 60_f64, s: 1_f64, l: 0.5_f64 });
//! ```

/// Color represented in HSL
#[derive(Debug, PartialEq, PartialOrd, Default)]
pub struct HSL {
    /// Hue in 0-360 degree
    pub h: f64,
    /// Saturation in 0...1 (percent)
    pub s: f64,
    /// Luminosity in 0...1 (percent)
    pub l: f64,
}

impl HSL {
    /// Convert RGB pixel value to HSL
    ///
    /// Expects RGB pixel to be a slice of three `u8`s representing the red, green and blue values.
    ///
    /// ```rust
    /// use hsl::HSL;
    /// let blue = HSL::from_rgb(&[0, 0, 255]);
    /// ```
    ///
    /// Algorithm from [go-color] by Brandon Thomson <bt@brandonthomson.com>. (Iternally converts
    /// the pixel to RGB before converting it to HSL.)
    ///
    /// [go-color]: https://github.com/bthomson/go-color
    #[cfg_attr(feature = "dev", allow(float_cmp))]
    pub fn from_rgb(rgb: &[u8]) -> HSL {
        use std::cmp::{max, min};

        let mut h: f64;
        let s: f64;
        let l: f64;

        let (r, g, b) = (rgb[0], rgb[1], rgb[2]);

        let max = max(max(r, g), b);
        let min = min(min(r, g), b);

        // Normalized RGB: Divide everything by 255 to get percentages of colors.
        let (r, g, b) = (r as f64 / 255_f64,
                         g as f64 / 255_f64,
                         b as f64 / 255_f64);
        let (min, max) = (min as f64 / 255_f64, max as f64 / 255_f64);

        // Luminosity is the average of the max and min rgb color intensities.
        l = (max + min) / 2_f64;

        // Saturation
        let delta: f64 = max - min;
        if delta == 0_f64 {
    		// it's gray
            return HSL { h: 0_f64, s: 0_f64, l: l };
        }

        // it's not gray
        if l < 0.5_f64 {
            s = delta / (max + min);
        } else {
            s = delta / (2_f64 - max - min);
        }

        // Hue
        let r2 = (((max - r) / 6_f64) + (delta / 2_f64)) / delta;
        let g2 = (((max - g) / 6_f64) + (delta / 2_f64)) / delta;
        let b2 = (((max - b) / 6_f64) + (delta / 2_f64)) / delta;

        h = match max {
            x if x == r => b2 - g2,
            x if x == g => (1_f64 / 3_f64) + r2 - b2,
            _ => (2_f64 / 3_f64) + g2 - r2,
        };

        // Fix wraparounds
        if h < 0 as f64 {
            h += 1_f64;
        } else if h > 1 as f64 {
            h -= 1_f64;
        }

        // Hue is precise to milli-degrees, e.g. `74.52deg`.
        let h_degrees = (h * 360_f64 * 100_f64).round() / 100_f64;

        HSL { h: h_degrees, s: s, l: l }
    }

    /// Convert HSL color to RGB
    ///
    /// ```rust
    /// use hsl::HSL;
    ///
    /// let cyan = HSL { h: 180_f64, s: 1_f64, l: 0.5_f64 };
    /// assert_eq!(cyan.to_rgb(), (0, 255, 255));
    /// ```
    pub fn to_rgb(&self) -> (u8, u8, u8) {
        if self.s == 0.0 {
            // Achromatic, i.e., grey.
            let l = percent_to_byte(self.l);
            return (l, l, l);
        }

        let h = self.h / 360.0; // treat this as 0..1 instead of degrees
        let s = self.s;
        let l = self.l;

        let q = if l < 0.5 {
            l * (1.0 + s)
        } else {
            l + s - (l * s)
        };
        let p = 2.0 * l - q;

        (percent_to_byte(hue_to_rgb(p, q, h + 1.0 / 3.0)),
         percent_to_byte(hue_to_rgb(p, q, h)),
         percent_to_byte(hue_to_rgb(p, q, h - 1.0 / 3.0)))
    }
}

fn percent_to_byte(percent: f64) -> u8 {
    (percent * 255.0).round() as u8
}

/// Convert Hue to RGB Ratio
///
/// From <https://github.com/jariz/vibrant.js/> by Jari Zwarts
fn hue_to_rgb(p: f64, q: f64, t: f64) -> f64 {
    // Normalize
    let t = if t < 0.0 {
        t + 1.0
    } else if t > 1.0 {
        t - 1.0
    } else {
        t
    };

    if t < 1.0 / 6.0 {
        p + (q - p) * 6.0 * t
    } else if t < 1.0 / 2.0 {
        q
    } else if t < 2.0 / 3.0 {
        p + (q - p) * (2.0 / 3.0 - t) * 6.0
    } else {
        p
    }
}
<|endoftext|>


<commit_before>use std::num;
use std::str;
use std::fmt;
use std::io;
use std::io::Read;

const MAX_PARAMS_SIZE: usize = 1024;
const Y4M_MAGICK: &'static [u8] = b"YUV4MPEG2 ";
const FRAME_MAGICK: &'static [u8] = b"FRAME";
const TERMINATOR: u8 = 0x0A;
const SEPARATOR: u8 = b' ';

#[derive(Debug)]
pub enum Error {
    EOF,
    // TODO(Kagami): Better granularity of parse errors.
    ParseError,
    IoError(io::Error),
}

trait EnhancedRead {
    fn read_until(&mut self, ch: u8, buf: &mut [u8]) -> Result<usize, Error>;
    // While io::Read::read_exact is unstable.
    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error>;
}

impl<R: Read> EnhancedRead for R {
    // Current implementation does one `read` call per byte. This might be a
    // bit slow for long headers but it simplifies other things: we don't need
    // to check whether start of the next frame is already read and so on.
    fn read_until(&mut self, ch: u8, buf: &mut [u8]) -> Result<usize, Error> {
        let mut collected = 0;
        while collected < buf.len() {
            let chunk_size = try!(self.read(&mut buf[collected..collected+1]));
            if chunk_size == 0 {
                return Err(Error::EOF);
            }
            if buf[collected] == ch {
                return Ok(collected);
            }
            collected += chunk_size;
        }
        Err(Error::ParseError)
    }

    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error> {
        let mut collected = 0;
        while collected < buf.len() {
            let chunk_size = try!(self.read(&mut buf[collected..]));
            if chunk_size == 0 {
                return Err(Error::EOF);
            }
            collected += chunk_size;
        }
        Ok(())
    }
}

// TODO(Kagami): >8bit pixel formats:
// yuv4mpeg can only handle yuv444p, yuv422p, yuv420p, yuv411p and gray8 pixel
// formats. And using 'strict -1' also yuv444p9, yuv422p9, yuv420p9, yuv444p10,
// yuv422p10, yuv420p10, yuv444p12, yuv422p12, yuv420p12, yuv444p14, yuv422p14,
// yuv420p14, yuv444p16, yuv422p16, yuv420p16 and gray16 pixel formats,
// (c) ffmpeg.
#[derive(Debug)]
pub enum Colorspace {
    Cmono,
    C420,
    C422,
    C444,
    C420jpeg,
    C420paldv,
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error { Error::IoError(err) }
}

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

impl From<num::ParseIntError> for Error {
    fn from(_: num::ParseIntError) -> Error { Error::ParseError }
}

pub struct Decoder<R: Read> {
    reader: R,
    params_buf: Vec<u8>,
    frame_buf: Vec<u8>,
    raw_params: Vec<u8>,
    width: usize,
    height: usize,
    colorspace: Option<Colorspace>,
    y_len: usize,
    u_len: usize,
}

impl<R: Read> Decoder<R> {
    pub fn new(mut reader: R) -> Result<Decoder<R>, Error> {
        let mut params_buf = vec![0;MAX_PARAMS_SIZE];
        let end_params_pos = try!(reader.read_until(TERMINATOR, &mut params_buf));
        if end_params_pos < Y4M_MAGICK.len() || !params_buf.starts_with(Y4M_MAGICK) {
            return Err(Error::ParseError);
        }
        let raw_params = (&params_buf[Y4M_MAGICK.len()..end_params_pos]).to_owned();
        let mut width = 0;
        let mut height = 0;
        let mut csp = None;
        for param in raw_params.split(|&b| b == SEPARATOR) {
            if param.len() < 1 { continue }
            let (name, value) = (param[0], &param[1..]);
            // TODO(Kagami): frame rate, interlacing, pixel aspect, comment.
            match name {
                b'W' => { width = try!(Self::bytes2int(value)) },
                b'H' => { height = try!(Self::bytes2int(value)) },
                b'C' => {
                    csp = match value {
                        b"mono" => Some(Colorspace::Cmono),
                        b"420" => Some(Colorspace::C420),
                        b"422" => Some(Colorspace::C422),
                        b"444" => Some(Colorspace::C444),
                        b"420jpeg" => Some(Colorspace::C420jpeg),
                        b"420paldv" => Some(Colorspace::C420paldv),
                        _ => None,
                    };
                },
                _ => {},
            }
        }
        if width == 0 || height == 0 { return Err(Error::ParseError) }
        let (y_len, u_len, v_len) = Self::get_plane_sizes(width, height, &csp);
        let frame_size = y_len + u_len + v_len;
        let frame_buf = vec![0;frame_size];
        Ok(Decoder {
            reader: reader,
            params_buf: params_buf,
            frame_buf: frame_buf,
            raw_params: raw_params,
            width: width,
            height: height,
            colorspace: csp,
            y_len: y_len,
            u_len: u_len,
        })
    }

    fn bytes2int(data: &[u8]) -> Result<usize, Error> {
        // A bit kludgy but seems like there is no other way.
        Ok(try!(try!(str::from_utf8(data)).parse()))
    }

    fn get_plane_sizes(
        width: usize, height: usize, colorspace: &Option<Colorspace>,
    ) -> (usize, usize, usize) {
        let pixels = width * height;
        let c420_sizes = (pixels, pixels/4, pixels/4);
        match *colorspace {
            Some(Colorspace::Cmono) => (pixels, 0, 0),
            Some(Colorspace::C420) => c420_sizes,
            Some(Colorspace::C422) => (pixels, pixels/2, pixels/2),
            Some(Colorspace::C444) => (pixels, pixels, pixels),
            Some(Colorspace::C420jpeg) => c420_sizes,
            Some(Colorspace::C420paldv) => c420_sizes,
            None => c420_sizes,
        }
    }

    /// Iterate over frames, without heap allocations. End of input is
    /// indicated by `Error::EOF`.
    pub fn next_frame<'a>(&'a mut self) -> Result<Frame<'a>, Error> {
        let end_params_pos = try!(self.reader.read_until(TERMINATOR, &mut self.params_buf));
        if end_params_pos < FRAME_MAGICK.len() || !self.params_buf.starts_with(FRAME_MAGICK) {
            return Err(Error::ParseError);
        }
        // We don't parse frame params currently but user has access to them.
        let raw_params = (&self.params_buf[FRAME_MAGICK.len()..end_params_pos]).to_owned();
        try!(self.reader.read_exact(&mut self.frame_buf));
        Ok(Frame {
            planes: [
                &self.frame_buf[0..self.y_len],
                &self.frame_buf[self.y_len..self.y_len+self.u_len],
                &self.frame_buf[self.y_len+self.u_len..],
            ],
            raw_params: raw_params,
        })
    }

    pub fn get_width(&self) -> usize { self.width }
    pub fn get_height(&self) -> usize { self.height }
    /// Return file colorspace.
    ///
    /// **NOTE:** normally all .y4m should have colorspace param, but there are
    /// files encoded without that tag and it's unclear what should we do in
    /// that case. Currently C420 is implied by default as per ffmpeg behavior.
    pub fn get_colorspace(&self) -> &Option<Colorspace> { &self.colorspace }
    pub fn get_raw_params(&self) -> &[u8] { &self.raw_params }
}

impl<R: Read> fmt::Debug for Decoder<R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "y4m::Decoder<w={}, h={}>", self.width, self.height)
    }
}

#[derive(Debug)]
pub struct Frame<'a> {
    planes: [&'a [u8];3],
    raw_params: Vec<u8>,
}

impl<'a> Frame<'a> {
    pub fn get_y_plane(&self) -> &[u8] { self.planes[0] }
    pub fn get_u_plane(&self) -> &[u8] { self.planes[1] }
    pub fn get_v_plane(&self) -> &[u8] { self.planes[2] }
    pub fn get_raw_params(&self) -> &[u8] { &self.raw_params }
}

/// Create a new decoder instance. Alias for `Decoder::new`.
pub fn decode<R: Read>(reader: R) -> Result<Decoder<R>, Error> {
    Decoder::new(reader)
}
<commit_msg>Some decoding fixes<commit_after>use std::num;
use std::str;
use std::fmt;
use std::io;
use std::io::Read;

const MAX_PARAMS_SIZE: usize = 1024;
const FILE_MAGICK: &'static [u8] = b"YUV4MPEG2 ";
const FRAME_MAGICK: &'static [u8] = b"FRAME";
const TERMINATOR: u8 = 0x0A;
const SEPARATOR: u8 = b' ';

#[derive(Debug)]
pub enum Error {
    /// End of the file. Technically not an error, but it's easier to process
    /// that way.
    EOF,
    // TODO(Kagami): Better granularity of parse errors.
    ParseError,
    IoError(io::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error { Error::IoError(err) }
}

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

impl From<num::ParseIntError> for Error {
    fn from(_: num::ParseIntError) -> Error { Error::ParseError }
}

trait EnhancedRead {
    fn read_until(&mut self, ch: u8, buf: &mut [u8]) -> Result<usize, Error>;
    // While io::Read::read_exact is unstable.
    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error>;
}

impl<R: Read> EnhancedRead for R {
    // Current implementation does one `read` call per byte. This might be a
    // bit slow for long headers but it simplifies things: we don't need to
    // check whether start of the next frame is already read and so on.
    fn read_until(&mut self, ch: u8, buf: &mut [u8]) -> Result<usize, Error> {
        let mut collected = 0;
        while collected < buf.len() {
            let chunk_size = try!(self.read(&mut buf[collected..collected+1]));
            if chunk_size == 0 {
                return Err(Error::EOF);
            }
            if buf[collected] == ch {
                return Ok(collected);
            }
            collected += chunk_size;
        }
        Err(Error::ParseError)
    }

    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error> {
        let mut collected = 0;
        while collected < buf.len() {
            let chunk_size = try!(self.read(&mut buf[collected..]));
            if chunk_size == 0 {
                return Err(Error::EOF);
            }
            collected += chunk_size;
        }
        Ok(())
    }
}

// TODO(Kagami): >8bit pixel formats:
// yuv4mpeg can only handle yuv444p, yuv422p, yuv420p, yuv411p and gray8 pixel
// formats. And using 'strict -1' also yuv444p9, yuv422p9, yuv420p9, yuv444p10,
// yuv422p10, yuv420p10, yuv444p12, yuv422p12, yuv420p12, yuv444p14, yuv422p14,
// yuv420p14, yuv444p16, yuv422p16, yuv420p16 and gray16 pixel formats,
// (c) ffmpeg.
#[derive(Debug)]
pub enum Colorspace {
    Cmono,
    C420,
    C422,
    C444,
    C420jpeg,
    C420paldv,
}

pub struct Decoder<R: Read> {
    reader: R,
    params_buf: Vec<u8>,
    frame_buf: Vec<u8>,
    raw_params: Vec<u8>,
    width: usize,
    height: usize,
    colorspace: Option<Colorspace>,
    y_len: usize,
    u_len: usize,
}

impl<R: Read> Decoder<R> {
    pub fn new(mut reader: R) -> Result<Decoder<R>, Error> {
        let mut params_buf = vec![0;MAX_PARAMS_SIZE];
        let end_params_pos = try!(reader.read_until(TERMINATOR, &mut params_buf));
        if end_params_pos < FILE_MAGICK.len() || !params_buf.starts_with(FILE_MAGICK) {
            return Err(Error::ParseError);
        }
        let raw_params = (&params_buf[FILE_MAGICK.len()..end_params_pos]).to_owned();
        let mut width = 0;
        let mut height = 0;
        let mut csp = None;
        // We shouldn't convert it to string because encoding is unspecified.
        for param in raw_params.split(|&b| b == SEPARATOR) {
            if param.len() < 1 { continue }
            let (name, value) = (param[0], &param[1..]);
            // TODO(Kagami): frame rate, interlacing, pixel aspect, comment.
            match name {
                b'W' => { width = try!(Self::bytes2int(value)) },
                b'H' => { height = try!(Self::bytes2int(value)) },
                b'C' => {
                    csp = match value {
                        b"mono" => Some(Colorspace::Cmono),
                        b"420" => Some(Colorspace::C420),
                        b"422" => Some(Colorspace::C422),
                        b"444" => Some(Colorspace::C444),
                        b"420jpeg" => Some(Colorspace::C420jpeg),
                        b"420paldv" => Some(Colorspace::C420paldv),
                        _ => None,
                    };
                },
                _ => {},
            }
        }
        if width == 0 || height == 0 { return Err(Error::ParseError) }
        let (y_len, u_len, v_len) = Self::get_plane_sizes(width, height, &csp);
        let frame_size = y_len + u_len + v_len;
        let frame_buf = vec![0;frame_size];
        Ok(Decoder {
            reader: reader,
            params_buf: params_buf,
            frame_buf: frame_buf,
            raw_params: raw_params,
            width: width,
            height: height,
            colorspace: csp,
            y_len: y_len,
            u_len: u_len,
        })
    }

    fn bytes2int(data: &[u8]) -> Result<usize, Error> {
        // A bit kludgy but seems like there is no other way.
        Ok(try!(try!(str::from_utf8(data)).parse()))
    }

    fn get_plane_sizes(
        width: usize, height: usize, colorspace: &Option<Colorspace>,
    ) -> (usize, usize, usize) {
        let pixels = width * height;
        let c420_sizes = (pixels, pixels/4, pixels/4);
        match *colorspace {
            Some(Colorspace::Cmono) => (pixels, 0, 0),
            Some(Colorspace::C420) => c420_sizes,
            Some(Colorspace::C422) => (pixels, pixels/2, pixels/2),
            Some(Colorspace::C444) => (pixels, pixels, pixels),
            Some(Colorspace::C420jpeg) => c420_sizes,
            Some(Colorspace::C420paldv) => c420_sizes,
            None => c420_sizes,
        }
    }

    /// Iterate over frames, without extra heap allocations. End of input is
    /// indicated by `Error::EOF`.
    pub fn next_frame<'a>(&'a mut self) -> Result<Frame<'a>, Error> {
        let end_params_pos = try!(self.reader.read_until(TERMINATOR, &mut self.params_buf));
        if end_params_pos < FRAME_MAGICK.len() || !self.params_buf.starts_with(FRAME_MAGICK) {
            return Err(Error::ParseError);
        }
        // We don't parse frame params currently but user has access to them.
        let start_params_pos = FRAME_MAGICK.len();
        let raw_params = if end_params_pos - start_params_pos > 0 {
            // Check for extra space.
            if self.params_buf[start_params_pos] != SEPARATOR {
                return Err(Error::ParseError);
            }
            Some((&self.params_buf[start_params_pos+1..end_params_pos]).to_owned())
        } else {
            None
        };
        try!(self.reader.read_exact(&mut self.frame_buf));
        Ok(Frame {
            planes: [
                &self.frame_buf[0..self.y_len],
                &self.frame_buf[self.y_len..self.y_len+self.u_len],
                &self.frame_buf[self.y_len+self.u_len..],
            ],
            raw_params: raw_params,
        })
    }

    pub fn get_width(&self) -> usize { self.width }
    pub fn get_height(&self) -> usize { self.height }
    /// Return file colorspace.
    ///
    /// **NOTE:** normally all .y4m should have colorspace param, but there are
    /// files encoded without that tag and it's unclear what should we do in
    /// that case. Currently C420 is implied by default as per ffmpeg behavior.
    pub fn get_colorspace(&self) -> &Option<Colorspace> { &self.colorspace }
    pub fn get_raw_params(&self) -> &[u8] { &self.raw_params }
}

impl<R: Read> fmt::Debug for Decoder<R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "y4m::Decoder<w={}, h={}>", self.width, self.height)
    }
}

#[derive(Debug)]
pub struct Frame<'a> {
    planes: [&'a [u8];3],
    raw_params: Option<Vec<u8>>,
}

impl<'a> Frame<'a> {
    pub fn get_y_plane(&self) -> &[u8] { self.planes[0] }
    pub fn get_u_plane(&self) -> &[u8] { self.planes[1] }
    pub fn get_v_plane(&self) -> &[u8] { self.planes[2] }
    pub fn get_raw_params(&self) -> Option<&[u8]> { self.raw_params.as_ref().map(|v| &v[..]) }
}

/// Create a new decoder instance. Alias for `Decoder::new`.
pub fn decode<R: Read>(reader: R) -> Result<Decoder<R>, Error> {
    Decoder::new(reader)
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://docs.rs/twitter-stream/0.10.0-alpha.5")]

/*!
# Twitter Stream

A library for listening on Twitter Streaming API.

## Usage

Add `twitter-stream` to your dependencies in your project's `Cargo.toml`:

```toml
[dependencies]
futures = "0.3"
tokio = { version = "0.2", features = ["macros"] }
twitter-stream = "=0.10.0-alpha.5"
```

## Overview

Here is a basic example that prints public mentions to @Twitter in JSON format:

```rust,no_run
use futures::prelude::*;
use twitter_stream::Token;

# #[tokio::main]
# async fn main() {
let token = Token::new("consumer_key", "consumer_secret", "access_key", "access_secret");

twitter_stream::Builder::filter(token)
    .track("@Twitter")
    .listen()
    .try_flatten_stream()
    .try_for_each(|json| {
        println!("{}", json);
        future::ok(())
    })
    .await
    .unwrap();
# }
```
*/

#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(intra_doc_link_resolution_failure)]

#[macro_use]
mod util;

pub mod builder;
pub mod error;
#[cfg(feature = "hyper")]
#[cfg_attr(docsrs, doc(cfg(feature = "hyper")))]
pub mod hyper;
pub mod service;

mod gzip;
mod token;

pub use oauth::Credentials;

pub use crate::builder::Builder;
pub use crate::error::Error;
pub use crate::token::Token;

use std::future::Future;
use std::pin::Pin;
use std::str;
use std::task::{Context, Poll};

use bytes::Bytes;
use futures_core::Stream;
use futures_util::ready;
use http::header::CONTENT_ENCODING;
use http::response::Parts;
use http::Response;
use http::StatusCode;
use http_body::Body;
use pin_project_lite::pin_project;

use crate::gzip::MaybeGzip;
use crate::util::{HttpBodyAsStream, Lines};

pin_project! {
    /// A future returned by constructor methods
    /// which resolves to a `TwitterStream`.
    pub struct FutureTwitterStream<F> {
        #[pin]
        response: F,
    }
}

pin_project! {
    /// A listener for Twitter Streaming API.
    /// It yields JSON strings returned from the API.
    pub struct TwitterStream<B: Body> {
        #[pin]
        inner: Lines<MaybeGzip<HttpBodyAsStream<B>>>,
    }
}

#[cfg(feature = "hyper")]
impl<B: Body> TwitterStream<B> {
    /// A shorthand for `Builder::filter().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn filter<C, A>(token: Token<C, A>) -> crate::hyper::FutureTwitterStream
    where
        C: std::borrow::Borrow<str>,
        A: std::borrow::Borrow<str>,
    {
        Builder::filter(token).listen()
    }

    /// A shorthand for `Builder::sample().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn sample<C, A>(token: Token<C, A>) -> crate::hyper::FutureTwitterStream
    where
        C: std::borrow::Borrow<str>,
        A: std::borrow::Borrow<str>,
    {
        Builder::sample(token).listen()
    }
}

impl<F, B, E> Future for FutureTwitterStream<F>
where
    F: Future<Output = Result<Response<B>, E>>,
    B: Body,
{
    type Output = Result<TwitterStream<B>, Error<E>>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let res = match ready!(self.project().response.poll(cx)) {
            Ok(res) => res,
            Err(e) => return Poll::Ready(Err(Error::Service(e))),
        };
        let (parts, body) = res.into_parts();
        let Parts {
            status, headers, ..
        } = parts;

        if StatusCode::OK != status {
            return Poll::Ready(Err(Error::Http(status)));
        }

        let use_gzip = headers
            .get_all(CONTENT_ENCODING)
            .iter()
            .any(|e| e == "gzip");
        let inner = if use_gzip {
            Lines::new(gzip::gzip(HttpBodyAsStream::new(body)))
        } else {
            Lines::new(gzip::identity(HttpBodyAsStream::new(body)))
        };

        Poll::Ready(Ok(TwitterStream { inner }))
    }
}

impl<B> Stream for TwitterStream<B>
where
    B: Body,
{
    type Item = Result<string::String<Bytes>, Error<B::Error>>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let mut this = self.project();

        loop {
            let line = match ready!(this.inner.as_mut().poll_next(cx)?) {
                Some(t) => t,
                None => return std::task::Poll::Ready(None),
            };

            if line.iter().all(|&c| is_json_whitespace(c)) {
                continue;
            }

            str::from_utf8(&line).map_err(Error::Utf8)?;
            let line = unsafe {
                // Safety:
                // - We have checked above that `line` is valid as UTF-8.
                // - `Bytes` satisfies the requirements of `string::StableAsRef` trait
                // (https://github.com/carllerche/string/pull/17)
                string::String::<Bytes>::from_utf8_unchecked(line)
            };
            return Poll::Ready(Some(Ok(line)));
        }
    }
}

fn is_json_whitespace(c: u8) -> bool {
    // RFC7159 §2
    b" \t\n\r".contains(&c)
}
<commit_msg>Adjust wording of docs<commit_after>#![doc(html_root_url = "https://docs.rs/twitter-stream/0.10.0-alpha.5")]

/*!
# Twitter Stream

A library for listening on Twitter Streaming API.

## Usage

Add this to your `Cargo.toml`:

```toml
[dependencies]
futures = "0.3"
tokio = { version = "0.2", features = ["macros"] }
twitter-stream = "=0.10.0-alpha.5"
```

## Overview

Here is a basic example that prints public mentions to @Twitter in JSON format:

```rust,no_run
use futures::prelude::*;
use twitter_stream::Token;

# #[tokio::main]
# async fn main() {
let token = Token::new("consumer_key", "consumer_secret", "access_key", "access_secret");

twitter_stream::Builder::filter(token)
    .track("@Twitter")
    .listen()
    .try_flatten_stream()
    .try_for_each(|json| {
        println!("{}", json);
        future::ok(())
    })
    .await
    .unwrap();
# }
```
*/

#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(intra_doc_link_resolution_failure)]

#[macro_use]
mod util;

pub mod builder;
pub mod error;
#[cfg(feature = "hyper")]
#[cfg_attr(docsrs, doc(cfg(feature = "hyper")))]
pub mod hyper;
pub mod service;

mod gzip;
mod token;

pub use oauth::Credentials;

pub use crate::builder::Builder;
pub use crate::error::Error;
pub use crate::token::Token;

use std::future::Future;
use std::pin::Pin;
use std::str;
use std::task::{Context, Poll};

use bytes::Bytes;
use futures_core::Stream;
use futures_util::ready;
use http::header::CONTENT_ENCODING;
use http::response::Parts;
use http::Response;
use http::StatusCode;
use http_body::Body;
use pin_project_lite::pin_project;

use crate::gzip::MaybeGzip;
use crate::util::{HttpBodyAsStream, Lines};

pin_project! {
    /// A future returned by constructor methods
    /// which resolves to a `TwitterStream`.
    pub struct FutureTwitterStream<F> {
        #[pin]
        response: F,
    }
}

pin_project! {
    /// A listener for Twitter Streaming API.
    /// It yields JSON strings returned from the API.
    pub struct TwitterStream<B: Body> {
        #[pin]
        inner: Lines<MaybeGzip<HttpBodyAsStream<B>>>,
    }
}

#[cfg(feature = "hyper")]
impl<B: Body> TwitterStream<B> {
    /// A shorthand for `Builder::filter().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn filter<C, A>(token: Token<C, A>) -> crate::hyper::FutureTwitterStream
    where
        C: std::borrow::Borrow<str>,
        A: std::borrow::Borrow<str>,
    {
        Builder::filter(token).listen()
    }

    /// A shorthand for `Builder::sample().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn sample<C, A>(token: Token<C, A>) -> crate::hyper::FutureTwitterStream
    where
        C: std::borrow::Borrow<str>,
        A: std::borrow::Borrow<str>,
    {
        Builder::sample(token).listen()
    }
}

impl<F, B, E> Future for FutureTwitterStream<F>
where
    F: Future<Output = Result<Response<B>, E>>,
    B: Body,
{
    type Output = Result<TwitterStream<B>, Error<E>>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let res = match ready!(self.project().response.poll(cx)) {
            Ok(res) => res,
            Err(e) => return Poll::Ready(Err(Error::Service(e))),
        };
        let (parts, body) = res.into_parts();
        let Parts {
            status, headers, ..
        } = parts;

        if StatusCode::OK != status {
            return Poll::Ready(Err(Error::Http(status)));
        }

        let use_gzip = headers
            .get_all(CONTENT_ENCODING)
            .iter()
            .any(|e| e == "gzip");
        let inner = if use_gzip {
            Lines::new(gzip::gzip(HttpBodyAsStream::new(body)))
        } else {
            Lines::new(gzip::identity(HttpBodyAsStream::new(body)))
        };

        Poll::Ready(Ok(TwitterStream { inner }))
    }
}

impl<B> Stream for TwitterStream<B>
where
    B: Body,
{
    type Item = Result<string::String<Bytes>, Error<B::Error>>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let mut this = self.project();

        loop {
            let line = match ready!(this.inner.as_mut().poll_next(cx)?) {
                Some(t) => t,
                None => return std::task::Poll::Ready(None),
            };

            if line.iter().all(|&c| is_json_whitespace(c)) {
                continue;
            }

            str::from_utf8(&line).map_err(Error::Utf8)?;
            let line = unsafe {
                // Safety:
                // - We have checked above that `line` is valid as UTF-8.
                // - `Bytes` satisfies the requirements of `string::StableAsRef` trait
                // (https://github.com/carllerche/string/pull/17)
                string::String::<Bytes>::from_utf8_unchecked(line)
            };
            return Poll::Ready(Some(Ok(line)));
        }
    }
}

fn is_json_whitespace(c: u8) -> bool {
    // RFC7159 §2
    b" \t\n\r".contains(&c)
}
<|endoftext|>


<commit_before>#![cfg_attr(test, deny(missing_docs, warnings))]
#![forbid(unused_variables)]

use std::{fmt, mem};
use std::borrow::{Borrow, ToOwned};
use std::default::Default;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, Index, Range, RangeFrom, RangeFull, RangeTo};

/// An owned sequence of Unicode scalar values, equivalent to `String`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UString(Vec<char>);

/// A Unicode string slice, equivalent to `str`.
pub struct UStr([char]);

impl UString {
    pub fn remove(&mut self, idx: usize) -> char {
        self.0.remove(idx)
    }
}

impl UStr {
    /// Returns the number of Unicode scalar values in this string.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Retrieves the first character from a `&UStr` and returns it.
    ///
    /// This does not allocate a new string; instead, it returns a slice that points one character beyond the character that was shifted.
    ///
    /// If the slice does not contain any characters, None is returned instead.
    pub fn slice_shift_char(&self) -> Option<(char, &UStr)> {
        if self.len() == 0 {
            None
        } else {
            let ch = self[0];
            let next_s = &self[1..];
            Some((ch, next_s))
        }
    }
}

impl Borrow<UStr> for UString {
    fn borrow(&self) -> &UStr {
        &self
    }
}

impl Default for UString {
    fn default() -> UString {
        UString(Vec::new())
    }
}

impl Deref for UString {
    type Target = UStr;

    fn deref(&self) -> &UStr {
        unsafe {
            mem::transmute(&*self.0)
            // just so you can be clear what it is:
            //mem::transmute::<&[char], &UStr>(&*self.0)
        }
    }
}

impl From<Vec<char>> for UString {
    fn from(chars: Vec<char>) -> UString {
        UString(chars)
    }
}

impl<'a> From<&'a str> for UString {
    fn from(string: &'a str) -> UString {
        UString(string.chars().collect())
    }
}

impl<'a> From<&'a [char]> for UString {
    fn from(slice: &[char]) -> UString {
        UString(slice.to_vec())
    }
}

impl Hash for UString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl Index<usize> for UStr {
    type Output = char;

    fn index(&self, idx: usize) -> &char {
        &self.0[idx]
    }
}

impl Index<Range<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: Range<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFrom<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeFrom<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFull> for UStr {
    type Output = UStr;

    fn index(&self, _: RangeFull) -> &UStr {
        self
    }
}

impl Index<RangeTo<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeTo<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl ToOwned for UStr {
    type Owned = UString;

    fn to_owned(&self) -> UString {
        UString::from(self.0.to_owned())
    }
}

impl fmt::Display for UStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for c in &self.0 {
            try!(write!(f, "{}", c));
        }
        Ok(())
    }
}
<commit_msg>Implement From<String> for UString<commit_after>#![cfg_attr(test, deny(missing_docs, warnings))]
#![forbid(unused_variables)]

use std::{fmt, mem};
use std::borrow::{Borrow, ToOwned};
use std::default::Default;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, Index, Range, RangeFrom, RangeFull, RangeTo};

/// An owned sequence of Unicode scalar values, equivalent to `String`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UString(Vec<char>);

/// A Unicode string slice, equivalent to `str`.
pub struct UStr([char]);

impl UString {
    pub fn remove(&mut self, idx: usize) -> char {
        self.0.remove(idx)
    }
}

impl UStr {
    /// Returns the number of Unicode scalar values in this string.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Retrieves the first character from a `&UStr` and returns it.
    ///
    /// This does not allocate a new string; instead, it returns a slice that points one character beyond the character that was shifted.
    ///
    /// If the slice does not contain any characters, None is returned instead.
    pub fn slice_shift_char(&self) -> Option<(char, &UStr)> {
        if self.len() == 0 {
            None
        } else {
            let ch = self[0];
            let next_s = &self[1..];
            Some((ch, next_s))
        }
    }
}

impl Borrow<UStr> for UString {
    fn borrow(&self) -> &UStr {
        &self
    }
}

impl Default for UString {
    fn default() -> UString {
        UString(Vec::new())
    }
}

impl Deref for UString {
    type Target = UStr;

    fn deref(&self) -> &UStr {
        unsafe {
            mem::transmute(&*self.0)
            // just so you can be clear what it is:
            //mem::transmute::<&[char], &UStr>(&*self.0)
        }
    }
}

impl From<String> for UString {
    fn from(string: String) -> UString {
        UString(string.chars().collect())
    }
}

impl From<Vec<char>> for UString {
    fn from(chars: Vec<char>) -> UString {
        UString(chars)
    }
}

impl<'a> From<&'a str> for UString {
    fn from(string: &'a str) -> UString {
        UString(string.chars().collect())
    }
}

impl<'a> From<&'a [char]> for UString {
    fn from(slice: &[char]) -> UString {
        UString(slice.to_vec())
    }
}

impl Hash for UString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl Index<usize> for UStr {
    type Output = char;

    fn index(&self, idx: usize) -> &char {
        &self.0[idx]
    }
}

impl Index<Range<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: Range<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFrom<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeFrom<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFull> for UStr {
    type Output = UStr;

    fn index(&self, _: RangeFull) -> &UStr {
        self
    }
}

impl Index<RangeTo<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeTo<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl ToOwned for UStr {
    type Owned = UString;

    fn to_owned(&self) -> UString {
        UString::from(self.0.to_owned())
    }
}

impl fmt::Display for UStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for c in &self.0 {
            try!(write!(f, "{}", c));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::io::{BufReader, IoResult};

struct Triangle {
    normal: [f32, ..3],
    v1: [f32, ..3],
    v2: [f32, ..3],
    v3: [f32, ..3],
    attr_byte_count: u16
}

fn point_eq(lhs: [f32, ..3], rhs: [f32, ..3]) -> bool {
    lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2]
}

impl PartialEq for Triangle {
    fn eq(&self, rhs: &Triangle) -> bool {
        point_eq(self.normal, rhs.normal)
            && point_eq(self.v1, rhs.v1)
            && point_eq(self.v2, rhs.v2)
            && point_eq(self.v3, rhs.v3)
            && self.attr_byte_count == rhs.attr_byte_count
    }
}

impl Eq for Triangle {}

struct BinaryStlHeader {
    header: [u8, ..80],
    num_triangles: u32
}

pub struct BinaryStlFile {
    header: BinaryStlHeader,
    triangles: Vec<Triangle>
}

fn read_point<T: Reader>(input: &mut T) -> IoResult<[f32, ..3]> {
    let x1 = try!(input.read_le_f32());
    let x2 = try!(input.read_le_f32());
    let x3 = try!(input.read_le_f32());

    Ok([x1, x2, x3])
}

fn read_triangle<T: Reader>(input: &mut T) -> IoResult<Triangle> {
    let normal = try!(read_point(input));
    let v1 = try!(read_point(input));
    let v2 = try!(read_point(input));
    let v3 = try!(read_point(input));
    let attr_count = try!(input.read_le_u16());

    Ok(Triangle { normal: normal,
                  v1: v1, v2: v2, v3: v3,
                  attr_byte_count: attr_count })
}

pub fn read_stl<T: Reader>(input: &mut T) -> IoResult<BinaryStlFile> {
    let mut header = BinaryStlHeader { header: [0u8, ..80],
                                       num_triangles: 0 };

    // read the header
    try!(input.read_at_least(header.header.len(), &mut header.header));

    // TODO: check the header to make sure whether this is a binary
    // STL file.

    header.num_triangles = try!(input.read_le_u32());

    let mut triangles = Vec::new();
    for _ in range(0, header.num_triangles) {
        triangles.push(try!(read_triangle(input)));
    }

    Ok(BinaryStlFile {
        header: header,
        triangles: triangles
    })
}

fn write_point<T: Writer>(out: &mut T, p: [f32, ..3]) -> IoResult<()> {
    for x in p.iter() {
        try!(out.write_le_f32(*x));
    }
    Ok(())
}

pub fn write_stl<T: Writer>(out: &mut T, stl: &BinaryStlFile) -> IoResult<()> {
    assert!(stl.header.num_triangles as uint == stl.triangles.len());

    //write the header.
    try!(out.write(&stl.header.header));
    try!(out.write_le_u32(stl.header.num_triangles));

    // write all the triangles
    for t in stl.triangles.iter() {
        try!(write_point(out, t.normal));
        try!(write_point(out, t.v1));
        try!(write_point(out, t.v2));
        try!(write_point(out, t.v3));
        try!(out.write_le_u16(t.attr_byte_count));
    }

    Ok(())
}

#[test]
fn write_read() {
    // Make sure we can write and read a simple file.
    let file = BinaryStlFile {
        header: BinaryStlHeader { header: [0u8, ..80],
                                  num_triangles: 1 },
        triangles: vec![Triangle { normal: [0f32, 1f32, 0f32],
                                   v1: [0f32, 0f32, 0f32],
                                   v2: [0f32, 0f32, 1f32],
                                   v3: [1f32, 0f32, 1f32],
                                   attr_byte_count: 0 }]
    };

    let mut buffer = Vec::new();

    match write_stl(&mut buffer, &file) {
        Ok(_) => (),
        Err(_) => panic!()
    }

    match read_stl(&mut BufReader::new(buffer.as_slice())) {
        Ok(stl) => {
            assert!(stl.header.num_triangles == file.header.num_triangles);
            assert!(stl.triangles.len() == 1);
            assert!(stl.triangles[0] == file.triangles[0])
        },
        Err(_) => panic!()
    }
}
<commit_msg>updated for nightly rust + warnings<commit_after>#![feature(io)]
#![feature(core)]

use std::old_io::IoResult;

struct Triangle {
    normal: [f32; 3],
    v1: [f32; 3],
    v2: [f32; 3],
    v3: [f32; 3],
    attr_byte_count: u16
}

fn point_eq(lhs: [f32; 3], rhs: [f32; 3]) -> bool {
    lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2]
}

impl PartialEq for Triangle {
    fn eq(&self, rhs: &Triangle) -> bool {
        point_eq(self.normal, rhs.normal)
            && point_eq(self.v1, rhs.v1)
            && point_eq(self.v2, rhs.v2)
            && point_eq(self.v3, rhs.v3)
            && self.attr_byte_count == rhs.attr_byte_count
    }
}

impl Eq for Triangle {}

struct BinaryStlHeader {
    header: [u8; 80],
    num_triangles: u32
}

pub struct BinaryStlFile {
    header: BinaryStlHeader,
    triangles: Vec<Triangle>
}

fn read_point<T: Reader>(input: &mut T) -> IoResult<[f32; 3]> {
    let x1 = try!(input.read_le_f32());
    let x2 = try!(input.read_le_f32());
    let x3 = try!(input.read_le_f32());

    Ok([x1, x2, x3])
}

fn read_triangle<T: Reader>(input: &mut T) -> IoResult<Triangle> {
    let normal = try!(read_point(input));
    let v1 = try!(read_point(input));
    let v2 = try!(read_point(input));
    let v3 = try!(read_point(input));
    let attr_count = try!(input.read_le_u16());

    Ok(Triangle { normal: normal,
                  v1: v1, v2: v2, v3: v3,
                  attr_byte_count: attr_count })
}

pub fn read_stl<T: Reader>(input: &mut T) -> IoResult<BinaryStlFile> {
    let mut header = BinaryStlHeader { header: [0u8; 80],
                                       num_triangles: 0 };

    // read the header
    try!(input.read_at_least(header.header.len(), &mut header.header));

    // TODO: check the header to make sure whether this is a binary
    // STL file.

    header.num_triangles = try!(input.read_le_u32());

    let mut triangles = Vec::new();
    for _ in 0..header.num_triangles {
        triangles.push(try!(read_triangle(input)));
    }

    Ok(BinaryStlFile {
        header: header,
        triangles: triangles
    })
}

fn write_point<T: Writer>(out: &mut T, p: [f32; 3]) -> IoResult<()> {
    for x in p.iter() {
        try!(out.write_le_f32(*x));
    }
    Ok(())
}

pub fn write_stl<T: Writer>(out: &mut T, stl: &BinaryStlFile) -> IoResult<()> {
    assert!(stl.header.num_triangles as usize == stl.triangles.len());

    //write the header.
    try!(out.write_all(&stl.header.header));
    try!(out.write_le_u32(stl.header.num_triangles));

    // write all the triangles
    for t in stl.triangles.iter() {
        try!(write_point(out, t.normal));
        try!(write_point(out, t.v1));
        try!(write_point(out, t.v2));
        try!(write_point(out, t.v3));
        try!(out.write_le_u16(t.attr_byte_count));
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use std::old_io::BufReader;
    use super::{BinaryStlFile, BinaryStlHeader, write_stl, read_stl, Triangle};
    #[test]
    fn write_read() {
        // Make sure we can write and read a simple file.
        let file = BinaryStlFile {
            header: BinaryStlHeader { header: [0u8; 80],
                                      num_triangles: 1 },
            triangles: vec![Triangle { normal: [0f32, 1f32, 0f32],
                                       v1: [0f32, 0f32, 0f32],
                                       v2: [0f32, 0f32, 1f32],
                                       v3: [1f32, 0f32, 1f32],
                                       attr_byte_count: 0 }]
        };

        let mut buffer = Vec::new();

        match write_stl(&mut buffer, &file) {
            Ok(_) => (),
            Err(_) => panic!()
        }

        match read_stl(&mut BufReader::new(buffer.as_slice())) {
            Ok(stl) => {
                assert!(stl.header.num_triangles == file.header.num_triangles);
                assert!(stl.triangles.len() == 1);
                assert!(stl.triangles[0] == file.triangles[0])
            },
            Err(_) => panic!()
        }
    }
}
<|endoftext|>


<commit_before>/*!
# nalgebra

**nalgebra** is a linear algebra library written for Rust targeting:

* General-purpose linear algebra (still lacks a lot of features…)
* Real time computer graphics.
* Real time computer physics.

## Using **nalgebra**
You will need the last stable build of the [rust compiler](http://www.rust-lang.org)
and the official package manager: [cargo](https://github.com/rust-lang/cargo).

Simply add the following to your `Cargo.toml` file:

```.ignore
[dependencies]
nalgebra = "0.12"
```

Most useful functionalities of **nalgebra** are grouped in the root module `nalgebra::`.

However, the recommended way to use **nalgebra** is to import types and traits
explicitly, and call free-functions using the `na::` prefix:

```.rust
#[macro_use]
extern crate approx; // For the macro relative_eq!
extern crate nalgebra as na;
use na::{Vector3, Rotation3};

fn main() {
    let axis  = Vector3::x_axis();
    let angle = 1.57;
    let b     = Rotation3::from_axis_angle(&axis, angle);

    relative_eq!(b.axis().unwrap(), axis);
    relative_eq!(b.angle(), angle);
}
```

## Features
**nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra library, with
an optimized set of tools for computer graphics and physics. Those features include:

* A single parametrizable type `Matrix` for vectors, (square or rectangular) matrices, and slices
  with dimensions known either at compile-time (using type-level integers) or at runtime.
* Matrices and vectors with compile-time sizes are statically allocated while dynamic ones are
  allocated on the heap.
* Convenient aliases for low-dimensional matrices and vectors: `Vector1` to `Vector6` and
  `Matrix1x1` to `Matrix6x6` (including rectangular matrices like `Matrix2x5`.
* Points sizes known at compile time, and convenience aliases: `Point1` to `Point6`.
* Translation (seen as a transformation that composes by multiplication): `Translation2`,
  `Translation3`.
* Rotation matrices: `Rotation2`, `Rotation3`.
* Quaternions: `Quaternion`, `UnitQuaternion` (for 3D rotation).
* Unit complex numbers can be used for 2D rotation: `UnitComplex`.
* Algebraic entities with a norm equal to one: `Unit<T>`, e.g., `Unit<Vector3<f32>>`.
* Isometries (translation ⨯ rotation): `Isometry2`, `Isometry3`
* Similarity transformations (translation ⨯ rotation ⨯ uniform scale): `Similarity2`, `Similarity3`.
* Affine transformations stored as an homogeneous matrix: `Affine2`, `Affine3`.
* Projective (i.e. invertible) transformations stored as an homogeneous matrix: `Projective2`,
  `Projective3`.
* General transformations that does not have to be invertible, stored as an homogeneous matrix:
  `Transform2`, `Transform3`.
* 3D projections for computer graphics: `Perspective3`, `Orthographic3`.
* Linear algebra and data analysis operators: QR decomposition, eigen-decomposition.
* Implements traits from the [alga](https://crates.io/crates/alga) crate for
  generic programming.
*/

// #![feature(plugin)]
//
// #![plugin(clippy)]

#![deny(non_camel_case_types)]
#![deny(unused_parens)]
#![deny(non_upper_case_globals)]
#![deny(unused_qualifications)]
#![deny(unused_results)]
#![warn(missing_docs)]
#![doc(html_root_url = "http://nalgebra.org/rustdoc")]

#[cfg(feature = "arbitrary")]
extern crate quickcheck;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde_derive;
extern crate num_traits as num;
extern crate num_complex;
extern crate rand;
#[macro_use]
extern crate approx;
extern crate typenum;
extern crate generic_array;

extern crate alga;

pub mod core;
pub mod geometry;
mod traits;

pub use core::*;
pub use geometry::*;
pub use traits::*;

use std::cmp::{self, PartialOrd, Ordering};

use num::Signed;
use alga::general::{Identity, SupersetOf, MeetSemilattice, JoinSemilattice, Lattice, Inverse,
                    Multiplicative, Additive, AdditiveGroup};
use alga::linear::SquareMatrix as AlgaSquareMatrix;
use alga::linear::{InnerSpace, NormedSpace, FiniteDimVectorSpace, EuclideanSpace};

pub use alga::general::Id;

/*
 *
 * Multiplicative identity.
 *
 */
/// Gets the ubiquitous multiplicative identity element.
///
/// Same as `Id::new()`.
#[inline]
pub fn id() -> Id {
    Id::new()
}

/// Gets the multiplicative identity element.
#[inline]
pub fn one<T: Identity<Multiplicative>>() -> T {
    T::identity()
}

/// Gets the additive identity element.
#[inline]
pub fn zero<T: Identity<Additive>>() -> T {
    T::identity()
}

/// Gets the origin of the given point.
#[inline]
pub fn origin<P: EuclideanSpace>() -> P {
    P::origin()
}

/*
 *
 * Dimension
 *
 */
/// The dimension of the given algebraic entity seen as a vector space.
#[inline]
pub fn dimension<V: FiniteDimVectorSpace>() -> usize {
    V::dimension()
}

/*
 *
 * Ordering
 *
 */
// XXX: this is very naive and could probably be optimized for specific types.
// XXX: also, we might just want to use divisions, but assuming `val` is usually not far from `min`
// or `max`, would it still be more efficient?
/// Wraps `val` into the range `[min, max]` using modular arithmetics.
///
/// The range must not be empty.
#[inline]
pub fn wrap<T>(mut val: T, min: T, max: T) -> T
    where T: Copy + PartialOrd + AdditiveGroup {

    assert!(min < max, "Invalid wrapping bounds.");
    let width = max - min;

    if val < min {
        val += width;

        while val < min {
            val += width
        }

        val
    }
    else if val > max {
        val -= width;

        while val > max {
            val -= width
        }

        val
    }
    else {
        val
    }
}

/// Returns a reference to the input value clamped to the interval `[min, max]`.
///
/// In particular:
///     * If `min < val < max`, this returns `val`.
///     * If `val <= min`, this retuns `min`.
///     * If `val >= max`, this retuns `max`.
#[inline]
pub fn clamp<T: PartialOrd>(val: T, min: T, max: T) -> T {
    if val > min {
        if val < max {
            val
        }
        else {
            max
        }
    }
    else {
        min
    }
}

/// Same as `cmp::max`.
#[inline]
pub fn max<T: Ord>(a: T, b: T) -> T {
    cmp::max(a, b)
}

/// Same as `cmp::min`.
#[inline]
pub fn min<T: Ord>(a: T, b: T) -> T {
    cmp::min(a, b)
}

/// The absolute value of `a`.
#[inline]
pub fn abs<T: Signed>(a: &T) -> T {
    a.abs()
}

/// Returns the infimum of `a` and `b`.
#[inline]
pub fn inf<T: MeetSemilattice>(a: &T, b: &T) -> T {
    a.meet(b)
}

/// Returns the supremum of `a` and `b`.
#[inline]
pub fn sup<T: JoinSemilattice>(a: &T, b: &T) -> T {
    a.join(b)
}

/// Returns simultaneously the infimum and supremum of `a` and `b`.
#[inline]
pub fn inf_sup<T: Lattice>(a: &T, b: &T) -> (T, T) {
    a.meet_join(b)
}

/// Compare `a` and `b` using a partial ordering relation.
#[inline]
pub fn partial_cmp<T: PartialOrd>(a: &T, b: &T) -> Option<Ordering> {
    a.partial_cmp(b)
}

/// Returns `true` iff `a` and `b` are comparable and `a < b`.
#[inline]
pub fn partial_lt<T: PartialOrd>(a: &T, b: &T) -> bool {
    a.lt(b)
}

/// Returns `true` iff `a` and `b` are comparable and `a <= b`.
#[inline]
pub fn partial_le<T: PartialOrd>(a: &T, b: &T) -> bool {
    a.le(b)
}

/// Returns `true` iff `a` and `b` are comparable and `a > b`.
#[inline]
pub fn partial_gt<T: PartialOrd>(a: &T, b: &T) -> bool {
    a.gt(b)
}

/// Returns `true` iff `a` and `b` are comparable and `a >= b`.
#[inline]
pub fn partial_ge<T: PartialOrd>(a: &T, b: &T) -> bool {
    a.ge(b)
}

/// Return the minimum of `a` and `b` if they are comparable.
#[inline]
pub fn partial_min<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<&'a T> {
    if let Some(ord) = a.partial_cmp(b) {
        match ord {
            Ordering::Greater => Some(b),
            _                 => Some(a),
        }
    }
    else {
        None
    }
}

/// Return the maximum of `a` and `b` if they are comparable.
#[inline]
pub fn partial_max<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<&'a T> {
    if let Some(ord) = a.partial_cmp(b) {
        match ord {
            Ordering::Less => Some(b),
            _              => Some(a),
        }
    }
    else {
        None
    }
}

/// Clamp `value` between `min` and `max`. Returns `None` if `value` is not comparable to
/// `min` or `max`.
#[inline]
pub fn partial_clamp<'a, T: PartialOrd>(value: &'a T, min: &'a T, max: &'a T) -> Option<&'a T> {
    if let (Some(cmp_min), Some(cmp_max)) = (value.partial_cmp(min), value.partial_cmp(max)) {
        if cmp_min == Ordering::Less {
            Some(min)
        }
        else if cmp_max == Ordering::Greater {
            Some(max)
        }
        else {
            Some(value)
        }
    }
    else {
        None
    }
}

/// Sorts two values in increasing order using a partial ordering.
#[inline]
pub fn partial_sort2<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<(&'a T, &'a T)> {
    if let Some(ord) = a.partial_cmp(b) {
        match ord {
            Ordering::Less => Some((a, b)),
            _              => Some((b, a)),
        }
    }
    else {
        None
    }
}

/*
 * Inverse
 */

/// Tries to gets an inverted copy of a square matrix.
#[inline]
pub fn try_inverse<M: AlgaSquareMatrix>(m: &M) -> Option<M> {
    m.try_inverse()
}

/// Computes the multiplicative inverse of an (always invertible) algebraic entity.
#[inline]
pub fn inverse<M: Inverse<Multiplicative>>(m: &M) -> M {
    m.inverse()
}

/*
 * Inner vector space
 */

/// Computes the dot product of two vectors.
#[inline]
pub fn dot<V: FiniteDimVectorSpace>(a: &V, b: &V) -> V::Field {
    a.dot(b)
}

/// Computes the smallest angle between two vectors.
#[inline]
pub fn angle<V: InnerSpace>(a: &V, b: &V) -> V::Real {
    a.angle(b)
}

/*
 * Normed space
 */

/// Computes the L2 (euclidean) norm of a vector.
#[inline]
pub fn norm<V: NormedSpace>(v: &V) -> V::Field {
    v.norm()
}

/// Computes the squared L2 (euclidean) norm of the vector `v`.
#[inline]
pub fn norm_squared<V: NormedSpace>(v: &V) -> V::Field {
    v.norm_squared()
}

/// Computes the normalized version of the vector `v`.
#[inline]
pub fn normalize<V: NormedSpace>(v: &V) -> V {
    v.normalize()
}

/// Computes the normalized version of the vector `v` or returns `None` if its norm is smaller than `min_norm`.
#[inline]
pub fn try_normalize<V: NormedSpace>(v: &V, min_norm: V::Field) -> Option<V> {
    v.try_normalize(min_norm)
}

/*
 *
 * Point operations.
 *
 */
/// The center of two points.
#[inline]
pub fn center<P: EuclideanSpace>(p1: &P, p2: &P) -> P {
    P::from_coordinates((p1.coordinates() + p2.coordinates()) * convert(0.5))
}

/// The distance between two points.
#[inline]
pub fn distance<P: EuclideanSpace>(p1: &P, p2: &P) -> P::Real {
    (p2.coordinates() - p1.coordinates()).norm()
}

/// The squared distance between two points.
#[inline]
pub fn distance_squared<P: EuclideanSpace>(p1: &P, p2: &P) -> P::Real {
    (p2.coordinates() - p1.coordinates()).norm_squared()
}

/*
 * Cast
 */
/// Converts an object from one type to an equivalent or more general one.
#[inline]
pub fn convert<From, To: SupersetOf<From>>(t: From) -> To {
    To::from_subset(&t)
}

/// Attempts to convert an object to a more specific one.
#[inline]
pub fn try_convert<From: SupersetOf<To>, To>(t: From) -> Option<To> {
    t.to_subset()
}

/// Indicates if `::try_convert` will succeed without actually performing the conversion.
#[inline]
pub fn is_convertible<From: SupersetOf<To>, To>(t: &From) -> bool {
    t.is_in_subset()
}

/// Use with care! Same as `try_convert` but without any property checks.
#[inline]
pub unsafe fn convert_unchecked<From: SupersetOf<To>, To>(t: From) -> To {
    t.to_subset_unchecked()
}

/// Converts an object from one type to an equivalent or more general one.
#[inline]
pub fn convert_ref<From, To: SupersetOf<From>>(t: &From) -> To {
    To::from_subset(t)
}

/// Attempts to convert an object to a more specific one.
#[inline]
pub fn try_convert_ref<From: SupersetOf<To>, To>(t: &From) -> Option<To> {
    t.to_subset()
}

/// Use with care! Same as `try_convert` but without any property checks.
#[inline]
pub unsafe fn convert_ref_unchecked<From: SupersetOf<To>, To>(t: &From) -> To {
    t.to_subset_unchecked()
}
<commit_msg>Refer to other conversion method in documentation<commit_after>/*!
# nalgebra

**nalgebra** is a linear algebra library written for Rust targeting:

* General-purpose linear algebra (still lacks a lot of features…)
* Real time computer graphics.
* Real time computer physics.

## Using **nalgebra**
You will need the last stable build of the [rust compiler](http://www.rust-lang.org)
and the official package manager: [cargo](https://github.com/rust-lang/cargo).

Simply add the following to your `Cargo.toml` file:

```.ignore
[dependencies]
nalgebra = "0.12"
```

Most useful functionalities of **nalgebra** are grouped in the root module `nalgebra::`.

However, the recommended way to use **nalgebra** is to import types and traits
explicitly, and call free-functions using the `na::` prefix:

```.rust
#[macro_use]
extern crate approx; // For the macro relative_eq!
extern crate nalgebra as na;
use na::{Vector3, Rotation3};

fn main() {
    let axis  = Vector3::x_axis();
    let angle = 1.57;
    let b     = Rotation3::from_axis_angle(&axis, angle);

    relative_eq!(b.axis().unwrap(), axis);
    relative_eq!(b.angle(), angle);
}
```

## Features
**nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra library, with
an optimized set of tools for computer graphics and physics. Those features include:

* A single parametrizable type `Matrix` for vectors, (square or rectangular) matrices, and slices
  with dimensions known either at compile-time (using type-level integers) or at runtime.
* Matrices and vectors with compile-time sizes are statically allocated while dynamic ones are
  allocated on the heap.
* Convenient aliases for low-dimensional matrices and vectors: `Vector1` to `Vector6` and
  `Matrix1x1` to `Matrix6x6` (including rectangular matrices like `Matrix2x5`.
* Points sizes known at compile time, and convenience aliases: `Point1` to `Point6`.
* Translation (seen as a transformation that composes by multiplication): `Translation2`,
  `Translation3`.
* Rotation matrices: `Rotation2`, `Rotation3`.
* Quaternions: `Quaternion`, `UnitQuaternion` (for 3D rotation).
* Unit complex numbers can be used for 2D rotation: `UnitComplex`.
* Algebraic entities with a norm equal to one: `Unit<T>`, e.g., `Unit<Vector3<f32>>`.
* Isometries (translation ⨯ rotation): `Isometry2`, `Isometry3`
* Similarity transformations (translation ⨯ rotation ⨯ uniform scale): `Similarity2`, `Similarity3`.
* Affine transformations stored as an homogeneous matrix: `Affine2`, `Affine3`.
* Projective (i.e. invertible) transformations stored as an homogeneous matrix: `Projective2`,
  `Projective3`.
* General transformations that does not have to be invertible, stored as an homogeneous matrix:
  `Transform2`, `Transform3`.
* 3D projections for computer graphics: `Perspective3`, `Orthographic3`.
* Linear algebra and data analysis operators: QR decomposition, eigen-decomposition.
* Implements traits from the [alga](https://crates.io/crates/alga) crate for
  generic programming.
*/

// #![feature(plugin)]
//
// #![plugin(clippy)]

#![deny(non_camel_case_types)]
#![deny(unused_parens)]
#![deny(non_upper_case_globals)]
#![deny(unused_qualifications)]
#![deny(unused_results)]
#![warn(missing_docs)]
#![doc(html_root_url = "http://nalgebra.org/rustdoc")]

#[cfg(feature = "arbitrary")]
extern crate quickcheck;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde_derive;
extern crate num_traits as num;
extern crate num_complex;
extern crate rand;
#[macro_use]
extern crate approx;
extern crate typenum;
extern crate generic_array;

extern crate alga;

pub mod core;
pub mod geometry;
mod traits;

pub use core::*;
pub use geometry::*;
pub use traits::*;

use std::cmp::{self, PartialOrd, Ordering};

use num::Signed;
use alga::general::{Identity, SupersetOf, MeetSemilattice, JoinSemilattice, Lattice, Inverse,
                    Multiplicative, Additive, AdditiveGroup};
use alga::linear::SquareMatrix as AlgaSquareMatrix;
use alga::linear::{InnerSpace, NormedSpace, FiniteDimVectorSpace, EuclideanSpace};

pub use alga::general::Id;

/*
 *
 * Multiplicative identity.
 *
 */
/// Gets the ubiquitous multiplicative identity element.
///
/// Same as `Id::new()`.
#[inline]
pub fn id() -> Id {
    Id::new()
}

/// Gets the multiplicative identity element.
#[inline]
pub fn one<T: Identity<Multiplicative>>() -> T {
    T::identity()
}

/// Gets the additive identity element.
#[inline]
pub fn zero<T: Identity<Additive>>() -> T {
    T::identity()
}

/// Gets the origin of the given point.
#[inline]
pub fn origin<P: EuclideanSpace>() -> P {
    P::origin()
}

/*
 *
 * Dimension
 *
 */
/// The dimension of the given algebraic entity seen as a vector space.
#[inline]
pub fn dimension<V: FiniteDimVectorSpace>() -> usize {
    V::dimension()
}

/*
 *
 * Ordering
 *
 */
// XXX: this is very naive and could probably be optimized for specific types.
// XXX: also, we might just want to use divisions, but assuming `val` is usually not far from `min`
// or `max`, would it still be more efficient?
/// Wraps `val` into the range `[min, max]` using modular arithmetics.
///
/// The range must not be empty.
#[inline]
pub fn wrap<T>(mut val: T, min: T, max: T) -> T
    where T: Copy + PartialOrd + AdditiveGroup {

    assert!(min < max, "Invalid wrapping bounds.");
    let width = max - min;

    if val < min {
        val += width;

        while val < min {
            val += width
        }

        val
    }
    else if val > max {
        val -= width;

        while val > max {
            val -= width
        }

        val
    }
    else {
        val
    }
}

/// Returns a reference to the input value clamped to the interval `[min, max]`.
///
/// In particular:
///     * If `min < val < max`, this returns `val`.
///     * If `val <= min`, this retuns `min`.
///     * If `val >= max`, this retuns `max`.
#[inline]
pub fn clamp<T: PartialOrd>(val: T, min: T, max: T) -> T {
    if val > min {
        if val < max {
            val
        }
        else {
            max
        }
    }
    else {
        min
    }
}

/// Same as `cmp::max`.
#[inline]
pub fn max<T: Ord>(a: T, b: T) -> T {
    cmp::max(a, b)
}

/// Same as `cmp::min`.
#[inline]
pub fn min<T: Ord>(a: T, b: T) -> T {
    cmp::min(a, b)
}

/// The absolute value of `a`.
#[inline]
pub fn abs<T: Signed>(a: &T) -> T {
    a.abs()
}

/// Returns the infimum of `a` and `b`.
#[inline]
pub fn inf<T: MeetSemilattice>(a: &T, b: &T) -> T {
    a.meet(b)
}

/// Returns the supremum of `a` and `b`.
#[inline]
pub fn sup<T: JoinSemilattice>(a: &T, b: &T) -> T {
    a.join(b)
}

/// Returns simultaneously the infimum and supremum of `a` and `b`.
#[inline]
pub fn inf_sup<T: Lattice>(a: &T, b: &T) -> (T, T) {
    a.meet_join(b)
}

/// Compare `a` and `b` using a partial ordering relation.
#[inline]
pub fn partial_cmp<T: PartialOrd>(a: &T, b: &T) -> Option<Ordering> {
    a.partial_cmp(b)
}

/// Returns `true` iff `a` and `b` are comparable and `a < b`.
#[inline]
pub fn partial_lt<T: PartialOrd>(a: &T, b: &T) -> bool {
    a.lt(b)
}

/// Returns `true` iff `a` and `b` are comparable and `a <= b`.
#[inline]
pub fn partial_le<T: PartialOrd>(a: &T, b: &T) -> bool {
    a.le(b)
}

/// Returns `true` iff `a` and `b` are comparable and `a > b`.
#[inline]
pub fn partial_gt<T: PartialOrd>(a: &T, b: &T) -> bool {
    a.gt(b)
}

/// Returns `true` iff `a` and `b` are comparable and `a >= b`.
#[inline]
pub fn partial_ge<T: PartialOrd>(a: &T, b: &T) -> bool {
    a.ge(b)
}

/// Return the minimum of `a` and `b` if they are comparable.
#[inline]
pub fn partial_min<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<&'a T> {
    if let Some(ord) = a.partial_cmp(b) {
        match ord {
            Ordering::Greater => Some(b),
            _                 => Some(a),
        }
    }
    else {
        None
    }
}

/// Return the maximum of `a` and `b` if they are comparable.
#[inline]
pub fn partial_max<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<&'a T> {
    if let Some(ord) = a.partial_cmp(b) {
        match ord {
            Ordering::Less => Some(b),
            _              => Some(a),
        }
    }
    else {
        None
    }
}

/// Clamp `value` between `min` and `max`. Returns `None` if `value` is not comparable to
/// `min` or `max`.
#[inline]
pub fn partial_clamp<'a, T: PartialOrd>(value: &'a T, min: &'a T, max: &'a T) -> Option<&'a T> {
    if let (Some(cmp_min), Some(cmp_max)) = (value.partial_cmp(min), value.partial_cmp(max)) {
        if cmp_min == Ordering::Less {
            Some(min)
        }
        else if cmp_max == Ordering::Greater {
            Some(max)
        }
        else {
            Some(value)
        }
    }
    else {
        None
    }
}

/// Sorts two values in increasing order using a partial ordering.
#[inline]
pub fn partial_sort2<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<(&'a T, &'a T)> {
    if let Some(ord) = a.partial_cmp(b) {
        match ord {
            Ordering::Less => Some((a, b)),
            _              => Some((b, a)),
        }
    }
    else {
        None
    }
}

/*
 * Inverse
 */

/// Tries to gets an inverted copy of a square matrix.
#[inline]
pub fn try_inverse<M: AlgaSquareMatrix>(m: &M) -> Option<M> {
    m.try_inverse()
}

/// Computes the multiplicative inverse of an (always invertible) algebraic entity.
#[inline]
pub fn inverse<M: Inverse<Multiplicative>>(m: &M) -> M {
    m.inverse()
}

/*
 * Inner vector space
 */

/// Computes the dot product of two vectors.
#[inline]
pub fn dot<V: FiniteDimVectorSpace>(a: &V, b: &V) -> V::Field {
    a.dot(b)
}

/// Computes the smallest angle between two vectors.
#[inline]
pub fn angle<V: InnerSpace>(a: &V, b: &V) -> V::Real {
    a.angle(b)
}

/*
 * Normed space
 */

/// Computes the L2 (euclidean) norm of a vector.
#[inline]
pub fn norm<V: NormedSpace>(v: &V) -> V::Field {
    v.norm()
}

/// Computes the squared L2 (euclidean) norm of the vector `v`.
#[inline]
pub fn norm_squared<V: NormedSpace>(v: &V) -> V::Field {
    v.norm_squared()
}

/// Computes the normalized version of the vector `v`.
#[inline]
pub fn normalize<V: NormedSpace>(v: &V) -> V {
    v.normalize()
}

/// Computes the normalized version of the vector `v` or returns `None` if its norm is smaller than `min_norm`.
#[inline]
pub fn try_normalize<V: NormedSpace>(v: &V, min_norm: V::Field) -> Option<V> {
    v.try_normalize(min_norm)
}

/*
 *
 * Point operations.
 *
 */
/// The center of two points.
#[inline]
pub fn center<P: EuclideanSpace>(p1: &P, p2: &P) -> P {
    P::from_coordinates((p1.coordinates() + p2.coordinates()) * convert(0.5))
}

/// The distance between two points.
#[inline]
pub fn distance<P: EuclideanSpace>(p1: &P, p2: &P) -> P::Real {
    (p2.coordinates() - p1.coordinates()).norm()
}

/// The squared distance between two points.
#[inline]
pub fn distance_squared<P: EuclideanSpace>(p1: &P, p2: &P) -> P::Real {
    (p2.coordinates() - p1.coordinates()).norm_squared()
}

/*
 * Cast
 */
/// Converts an object from one type to an equivalent or more general one.
///
/// See also `::try_convert` for conversion to more specific types.
#[inline]
pub fn convert<From, To: SupersetOf<From>>(t: From) -> To {
    To::from_subset(&t)
}

/// Attempts to convert an object to a more specific one.
///
/// See also `::convert` for conversion to more general types.
#[inline]
pub fn try_convert<From: SupersetOf<To>, To>(t: From) -> Option<To> {
    t.to_subset()
}

/// Indicates if `::try_convert` will succeed without actually performing the conversion.
#[inline]
pub fn is_convertible<From: SupersetOf<To>, To>(t: &From) -> bool {
    t.is_in_subset()
}

/// Use with care! Same as `try_convert` but without any property checks.
#[inline]
pub unsafe fn convert_unchecked<From: SupersetOf<To>, To>(t: From) -> To {
    t.to_subset_unchecked()
}

/// Converts an object from one type to an equivalent or more general one.
#[inline]
pub fn convert_ref<From, To: SupersetOf<From>>(t: &From) -> To {
    To::from_subset(t)
}

/// Attempts to convert an object to a more specific one.
#[inline]
pub fn try_convert_ref<From: SupersetOf<To>, To>(t: &From) -> Option<To> {
    t.to_subset()
}

/// Use with care! Same as `try_convert` but without any property checks.
#[inline]
pub unsafe fn convert_ref_unchecked<From: SupersetOf<To>, To>(t: &From) -> To {
    t.to_subset_unchecked()
}
<|endoftext|>


<commit_before>
#![feature(unsafe_destructor)]
#[allow(dead_code)]

extern crate libc;
use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::{HashMap};
use mruby::{mrb_open,mrb_close,mrb_state,mrb_value,Struct_RClass,mrb_int};
mod mruby;

pub type MrbState = Rc<RefCell<*mut mrb_state>>;
pub type MrbClass = Rc<RefCell<*mut Struct_RClass>>;

pub struct Mrb {
    mrb : MrbState,
    clzs : RefCell<HashMap<String,MrbClass>>
}

#[deriving(PartialEq,Clone)]
pub struct Class {
    mrb : MrbState,
    clz : MrbClass
}

impl Mrb {

    pub fn new() -> Mrb {
        let mrb = unsafe {
            mrb_open()
        };
        let state = unsafe { *mrb };
        let clzs : RefCell<HashMap<String,MrbClass>> = RefCell::new(HashMap::new());
        let m = Mrb{ mrb:Rc::new(RefCell::new(mrb)),clzs:clzs };
        m.clzs.borrow_mut().insert(String::from_str("Object"),Rc::new(RefCell::new(state.object_class)));
        m.clzs.borrow_mut().insert(String::from_str("Class"),Rc::new(RefCell::new(state.class_class)));
        m.clzs.borrow_mut().insert(String::from_str("String"),Rc::new(RefCell::new(state.string_class)));
        m.clzs.borrow_mut().insert(String::from_str("Array"),Rc::new(RefCell::new(state.array_class)));
        m.clzs.borrow_mut().insert(String::from_str("Hash"),Rc::new(RefCell::new(state.hash_class)));
        m
    }

    pub fn close(&self) {
        if std::rc::is_unique(&self.mrb) {
            let state = self.get_mrb();
            unsafe {
                mrb_close(state);
            }
        }
    }

    #[inline(always)]
    fn get_mrb(&self) -> *mut mrb_state {
        *(self.mrb).borrow_mut()
    }

    pub fn get_class(&self,name:&str) -> Option<Class> {
        let mut h = self.clzs.borrow_mut();
        let clzname = String::from_str(name);
        if h.get(&clzname).is_some() {
                return Some(Class{mrb:self.mrb.clone(),clz:h.get(&clzname).unwrap().clone()})
        }
        let mclz = unsafe {
            mruby::mrb_class_get(self.get_mrb(),
                                 name.as_ptr() as *const libc::c_char)
        };
        if mclz.is_null() {
            None
        } else {
            let class = Class{mrb:self.mrb.clone(),clz:Rc::new(RefCell::new(mclz))};
            h.insert(clzname,class.clz.clone());
            Some(class)
        }
    }

    pub fn load(&self,code:&str) -> mrb_value {
        unsafe {
            let state = self.get_mrb();
            let mut sjmp = (*state).jmp;
            if sjmp as uint != 0 {
                panic!("jmp not null");
            }
            let jmp = libc::malloc(std::mem::size_of::<mruby::jmp_buf>() as libc::size_t) as *mut mruby::jmp_buf;
            if mruby::setjmp(*jmp) as int == 0 {
                sjmp = jmp;
                let val = mruby::mrb_load_string(state,code.as_ptr() as *const libc::c_char);
                sjmp = 0 as *mut _;
                return val;
            } else {
                mruby::mrb_print_error(state);
                panic!("fail to setjmp");
            }
            libc::free(jmp as *mut _);
        }
    }

    pub fn def_class(&self,name:&str,outer:&str) -> Option<Class> {
        if self.get_class(name).is_some() {
            panic!("class already have");
        }
        match self.get_class(outer) {
            Some(out_clz) => {
                let clz = unsafe {
                    mruby::mrb_define_class(self.get_mrb(),
                                 name.as_ptr() as *const libc::c_char,
                                 out_clz.get_clz()
                                 )
                };
                let class = Class{mrb:self.mrb.clone(),clz:Rc::new(RefCell::new(clz))};
                let mut h = self.clzs.borrow_mut();
                h.insert(String::from_str(name),class.clz.clone());
                Some(class)
            },
            None => {
                None
            }
        }
    }

    pub fn call(&self,v:&mrb_value,method:&str) {
        unsafe {
            mruby::mrb_funcall(self.get_mrb(),*v,
                                 method.as_ptr() as *const libc::c_char,0 as mrb_int);
        }
    }

    pub fn inspect(&self,v:&mrb_value) {
        self.call(v,"to_s");
    }

}

impl Class {
    #[inline(always)]
    fn get_clz(&self) -> *mut Struct_RClass {
        *(self.clz).borrow_mut()
    }

    #[inline(always)]
    fn get_mrb(&self) -> *mut mrb_state {
        *(self.mrb).borrow_mut()
    }

    fn new(&self) -> mrb_value {
        unsafe {
            mruby::mrb_obj_new(self.get_mrb(),self.get_clz(),0 as mrb_int,0 as *const _)
        }
    }
}
/*
#[unsafe_destructor]
impl Drop for RefCell<*mut mrb_state> {
    fn drop(&mut self) {
        let mrb = *self.borrow_mut();
        if !mrb.is_null() {
            println!("mrb pointer null");
            unsafe {
                mrb_close(mrb);
            }
        }
    }
}
*/

#[test]
fn test_mrb_open() {
    let m = Mrb::new();
    m.close();
}

#[test]
fn test_get_class() {
    let m = Mrb::new();
    let arr_clz = m.get_class("Array").unwrap();
    assert!(m.get_class("Class").is_some());
    assert!(m.get_class("Object").is_some());
    assert!(m.get_class("Hash").is_some());
    assert!(m.get_class("String").is_some());
    m.close();
    assert!(m.get_class("String").is_some());
    assert!(std::rc::strong_count(&arr_clz.mrb) == 2);
}

#[test]
fn test_obj_new() {
    let m = Mrb::new();
    let arr_clz = m.get_class("Array").unwrap();
    let v = arr_clz.new();
    m.inspect(&v);
    assert!(v.is_nil());
    m.close();
}

#[test]
fn test_load_str() {
    let m = Mrb::new();
    let mut v = m.load("def inc(a) a+1 end; return inc(2)");
    assert!(v.is_nil());
    m.call(&v,"to_s");
    m.close();
}

#[test]
fn test_def_class() {
    let m = Mrb::new();
    let hello = m.def_class("Hello","Object");
    assert!(hello.is_some());
    m.close();
}
<commit_msg>add HasState & HasClass<commit_after>
#![feature(unsafe_destructor)]
#[allow(dead_code)]

extern crate libc;
use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::{HashMap};
use mruby::{mrb_open,mrb_close,mrb_state,mrb_value,Struct_RClass,mrb_int};
mod mruby;

pub type MrbState = Rc<RefCell<*mut mrb_state>>;
pub type MrbClass = Rc<RefCell<*mut Struct_RClass>>;

pub struct Mrb {
    mrb : MrbState,
    clzs : RefCell<HashMap<String,MrbClass>>
}

#[deriving(PartialEq,Clone)]
pub struct Class {
    mrb : MrbState,
    clz : MrbClass
}

/// Traits for objects that has access to mrb_state.
/// Inspired by rust-hl-lua.
pub trait HasState {
    fn get_state(&self) -> *mut mrb_state;
}

impl HasState for Mrb {
    #[inline(always)]
    fn get_state(&self) -> *mut mrb_state {
        *(self.mrb).borrow_mut()
    }
}

impl HasState for Class {
    #[inline(always)]
    fn get_state(&self) -> *mut mrb_state {
        *(self.mrb).borrow_mut()
    }
}

/// Traits for objects that has access to Struct_RClass.
/// Inspired by rust-hl-lua.
pub trait HasClass {
    fn get_class(&self) -> *mut Struct_RClass;
}

impl HasClass for Class {
    #[inline(always)]
    fn get_class(&self) -> *mut Struct_RClass {
        *(self.clz).borrow_mut()
    }
}

impl Mrb {

    pub fn new() -> Mrb {
        let mrb = unsafe {
            mrb_open()
        };
        let state = unsafe { *mrb };
        let clzs : RefCell<HashMap<String,MrbClass>> = RefCell::new(HashMap::new());
        let m = Mrb{ mrb:Rc::new(RefCell::new(mrb)),clzs:clzs };
        m.clzs.borrow_mut().insert(String::from_str("Object"),Rc::new(RefCell::new(state.object_class)));
        m.clzs.borrow_mut().insert(String::from_str("Class"),Rc::new(RefCell::new(state.class_class)));
        m.clzs.borrow_mut().insert(String::from_str("String"),Rc::new(RefCell::new(state.string_class)));
        m.clzs.borrow_mut().insert(String::from_str("Array"),Rc::new(RefCell::new(state.array_class)));
        m.clzs.borrow_mut().insert(String::from_str("Hash"),Rc::new(RefCell::new(state.hash_class)));
        m
    }

    pub fn close(&self) {
        if std::rc::is_unique(&self.mrb) {
            let state = self.get_state();
            unsafe {
                mrb_close(state);
            }
        }
    }

    pub fn get_class(&self,name:&str) -> Option<Class> {
        let mut h = self.clzs.borrow_mut();
        let clzname = String::from_str(name);
        if h.get(&clzname).is_some() {
                return Some(Class{mrb:self.mrb.clone(),clz:h.get(&clzname).unwrap().clone()})
        }
        let mclz = unsafe {
            mruby::mrb_class_get(self.get_state(),
                                 name.as_ptr() as *const libc::c_char)
        };
        if mclz.is_null() {
            None
        } else {
            let class = Class{mrb:self.mrb.clone(),clz:Rc::new(RefCell::new(mclz))};
            h.insert(clzname,class.clz.clone());
            Some(class)
        }
    }

    pub fn load(&self,code:&str) -> mrb_value {
        unsafe {
            let state = self.get_state();
            let mut sjmp = (*state).jmp;
            if sjmp as uint != 0 {
                panic!("jmp not null");
            }
            let jmp = libc::malloc(std::mem::size_of::<mruby::jmp_buf>() as libc::size_t) as *mut mruby::jmp_buf;
            if mruby::setjmp(*jmp) as int == 0 {
                sjmp = jmp;
                let val = mruby::mrb_load_string(state,code.as_ptr() as *const libc::c_char);
                sjmp = 0 as *mut _;
                return val;
            } else {
                mruby::mrb_print_error(state);
                panic!("fail to setjmp");
            }
            libc::free(jmp as *mut _);
        }
    }

    pub fn def_class(&self,name:&str,outer:&str) -> Option<Class> {
        if self.get_class(name).is_some() {
            panic!("class already have");
        }
        match self.get_class(outer) {
            Some(out_clz) => {
                let clz = unsafe {
                    mruby::mrb_define_class(self.get_state(),
                                 name.as_ptr() as *const libc::c_char,
                                 out_clz.get_class()
                                 )
                };
                let class = Class{mrb:self.mrb.clone(),clz:Rc::new(RefCell::new(clz))};
                let mut h = self.clzs.borrow_mut();
                h.insert(String::from_str(name),class.clz.clone());
                Some(class)
            },
            None => {
                None
            }
        }
    }

    pub fn call(&self,v:&mrb_value,method:&str) {
        unsafe {
            mruby::mrb_funcall(self.get_state(),*v,
                                 method.as_ptr() as *const libc::c_char,0 as mrb_int);
        }
    }

    pub fn inspect(&self,v:&mrb_value) {
        self.call(v,"to_s");
    }

}

impl Class {
    fn new(&self) -> mrb_value {
        unsafe {
            mruby::mrb_obj_new(self.get_state(),self.get_class(),0 as mrb_int,0 as *const _)
        }
    }
}
/*
#[unsafe_destructor]
impl Drop for RefCell<*mut mrb_state> {
    fn drop(&mut self) {
        let mrb = *self.borrow_mut();
        if !mrb.is_null() {
            println!("mrb pointer null");
            unsafe {
                mrb_close(mrb);
            }
        }
    }
}
*/

#[test]
fn test_mrb_open() {
    let m = Mrb::new();
    m.close();
}

#[test]
fn test_get_class() {
    let m = Mrb::new();
    let arr_clz = m.get_class("Array").unwrap();
    assert!(m.get_class("Class").is_some());
    assert!(m.get_class("Object").is_some());
    assert!(m.get_class("Hash").is_some());
    assert!(m.get_class("String").is_some());
    m.close();
    assert!(m.get_class("String").is_some());
    assert!(std::rc::strong_count(&arr_clz.mrb) == 2);
}

#[test]
fn test_obj_new() {
    let m = Mrb::new();
    let arr_clz = m.get_class("Array").unwrap();
    let v = arr_clz.new();
    m.inspect(&v);
    assert!(v.is_nil());
    m.close();
}

#[test]
fn test_load_str() {
    let m = Mrb::new();
    let mut v = m.load("def inc(a) a+1 end; return inc(2)");
    assert!(v.is_nil());
    m.call(&v,"to_s");
    m.close();
}

#[test]
fn test_def_class() {
    let m = Mrb::new();
    let hello = m.def_class("Hello","Object");
    assert!(hello.is_some());
    m.close();
}
<|endoftext|>


<commit_before>
pub fn puzzle(input: &str) -> u32 {
    0
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Tile {
    Safe,
    Trap,
}

fn next_row(row: &[Tile]) -> Vec<Tile> {
    let mut x = vec![Tile::Safe];
    x.extend_from_slice(row);
    x.push(Tile::Safe);

    x.windows(3).map(|tiles| {
        next_tile(tiles[0], tiles[1], tiles[2])
    }).collect()
}

fn next_tile(left: Tile, center: Tile, right: Tile) -> Tile {
    use Tile::*;
    match (left, center, right) {
        (Trap, Trap, Safe) => Trap,
        (Safe, Trap, Trap) => Trap,
        (Trap, Safe, Safe) => Trap,
        (Safe, Safe, Trap) => Trap,
        _ => Safe,
    }
}

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

    #[test]
    fn safe() {
        assert_eq!(next_tile(Tile::Safe, Tile::Safe, Tile::Safe), Tile::Safe);
        assert_eq!(next_tile(Tile::Safe, Tile::Trap, Tile::Safe), Tile::Safe);
        assert_eq!(next_tile(Tile::Trap, Tile::Safe, Tile::Trap), Tile::Safe);
        assert_eq!(next_tile(Tile::Trap, Tile::Trap, Tile::Trap), Tile::Safe);
    }

    #[test]
    fn first_rule() {
        assert_eq!(next_tile(Tile::Trap, Tile::Trap, Tile::Safe), Tile::Trap);
    }

    #[test]
    fn second_rule() {
        assert_eq!(next_tile(Tile::Safe, Tile::Trap, Tile::Trap), Tile::Trap);
    }

    #[test]
    fn third_rule() {
        assert_eq!(next_tile(Tile::Trap, Tile::Safe, Tile::Safe), Tile::Trap);
    }

    #[test]
    fn fourth_rule() {
        assert_eq!(next_tile(Tile::Safe, Tile::Safe, Tile::Trap), Tile::Trap);
    }

    fn string_to_row(s: &str) -> Vec<Tile> {
        s.chars().map(|c| {
            match c {
                '.' => Tile::Safe,
                '^' => Tile::Trap,
                _ => panic!("unknown tile character {}", c),
            }
        }).collect()
    }

    #[test]
    fn row_at_a_time() {
        assert_eq!(next_row(&string_to_row("..^^.")), string_to_row(".^^^^"));
    }

}
<commit_msg>Extract a Row type<commit_after>
pub fn puzzle(input: &str) -> u32 {
    0
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Tile {
    Safe,
    Trap,
}

fn next_tile(left: Tile, center: Tile, right: Tile) -> Tile {
    use Tile::*;
    match (left, center, right) {
        (Trap, Trap, Safe) => Trap,
        (Safe, Trap, Trap) => Trap,
        (Trap, Safe, Safe) => Trap,
        (Safe, Safe, Trap) => Trap,
        _ => Safe,
    }
}

#[derive(Debug, Clone, PartialEq)]
struct Row(Vec<Tile>);

impl Row {
    fn next(&self) -> Row {
        let mut x = vec![Tile::Safe];
        x.extend_from_slice(&self.0);
        x.push(Tile::Safe);

        Row(x.windows(3).map(|tiles| {
            next_tile(tiles[0], tiles[1], tiles[2])
        }).collect())
    }
}

fn string_to_row(s: &str) -> Row {
    Row(s.chars().map(|c| {
        match c {
            '.' => Tile::Safe,
            '^' => Tile::Trap,
            _ => panic!("unknown tile character {}", c),
        }
    }).collect())
}

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

    #[test]
    fn safe() {
        assert_eq!(next_tile(Tile::Safe, Tile::Safe, Tile::Safe), Tile::Safe);
        assert_eq!(next_tile(Tile::Safe, Tile::Trap, Tile::Safe), Tile::Safe);
        assert_eq!(next_tile(Tile::Trap, Tile::Safe, Tile::Trap), Tile::Safe);
        assert_eq!(next_tile(Tile::Trap, Tile::Trap, Tile::Trap), Tile::Safe);
    }

    #[test]
    fn first_rule() {
        assert_eq!(next_tile(Tile::Trap, Tile::Trap, Tile::Safe), Tile::Trap);
    }

    #[test]
    fn second_rule() {
        assert_eq!(next_tile(Tile::Safe, Tile::Trap, Tile::Trap), Tile::Trap);
    }

    #[test]
    fn third_rule() {
        assert_eq!(next_tile(Tile::Trap, Tile::Safe, Tile::Safe), Tile::Trap);
    }

    #[test]
    fn fourth_rule() {
        assert_eq!(next_tile(Tile::Safe, Tile::Safe, Tile::Trap), Tile::Trap);
    }

    #[test]
    fn row_at_a_time() {
        assert_eq!(string_to_row("..^^.").next(), string_to_row(".^^^^"));
    }

}
<|endoftext|>