<commit_before>/// A style is a collection of properties that can format a string
/// using ANSI escape codes.
#[derive(PartialEq, Clone, Copy)]
#[cfg_attr(feature = "derive_serde_style", derive(serde::Deserialize, serde::Serialize))]
pub struct Style {

    /// The style's foreground colour, if it has one.
    pub foreground: Option<Colour>,

    /// The style's background colour, if it has one.
    pub background: Option<Colour>,

    /// Whether this style is bold.
    pub is_bold: bool,

    /// Whether this style is dimmed.
    pub is_dimmed: bool,

    /// Whether this style is italic.
    pub is_italic: bool,

    /// Whether this style is underlined.
    pub is_underline: bool,

    /// Whether this style is blinking.
    pub is_blink: bool,

    /// Whether this style has reverse colours.
    pub is_reverse: bool,

    /// Whether this style is hidden.
    pub is_hidden: bool,

    /// Whether this style is struckthrough.
    pub is_strikethrough: bool
}

impl Style {
    /// Creates a new Style with no differences.
    pub fn new() -> Style {
        Style::default()
    }

    /// Returns a `Style` with the bold property set.
    pub fn bold(&self) -> Style {
        Style { is_bold: true, .. *self }
    }

    /// Returns a `Style` with the dimmed property set.
    pub fn dimmed(&self) -> Style {
        Style { is_dimmed: true, .. *self }
    }

    /// Returns a `Style` with the italic property set.
    pub fn italic(&self) -> Style {
        Style { is_italic: true, .. *self }
    }

    /// Returns a `Style` with the underline property set.
    pub fn underline(&self) -> Style {
        Style { is_underline: true, .. *self }
    }

    /// Returns a `Style` with the blink property set.
    pub fn blink(&self) -> Style {
        Style { is_blink: true, .. *self }
    }

    /// Returns a `Style` with the reverse property set.
    pub fn reverse(&self) -> Style {
        Style { is_reverse: true, .. *self }
    }

    /// Returns a `Style` with the hidden property set.
    pub fn hidden(&self) -> Style {
        Style { is_hidden: true, .. *self }
    }

    /// Returns a `Style` with the hidden property set.
    pub fn strikethrough(&self) -> Style {
        Style { is_strikethrough: true, .. *self }
    }

    /// Returns a `Style` with the foreground colour property set.
    pub fn fg(&self, foreground: Colour) -> Style {
        Style { foreground: Some(foreground), .. *self }
    }

    /// Returns a `Style` with the background colour property set.
    pub fn on(&self, background: Colour) -> Style {
        Style { background: Some(background), .. *self }
    }

    /// Return true if this `Style` has no actual styles, and can be written
    /// without any control characters.
    pub fn is_plain(self) -> bool {
        self == Style::default()
    }
}

impl Default for Style {

    /// Returns a style with *no* properties set. Formatting text using this
    /// style returns the exact same text.
    ///
    /// ```
    /// use ansi_term::Style;
    /// assert_eq!(None,  Style::default().foreground);
    /// assert_eq!(None,  Style::default().background);
    /// assert_eq!(false, Style::default().is_bold);
    /// assert_eq!("txt", Style::default().paint("txt").to_string());
    /// ```
    fn default() -> Style {
        Style {
            foreground: None,
            background: None,
            is_bold: false,
            is_dimmed: false,
            is_italic: false,
            is_underline: false,
            is_blink: false,
            is_reverse: false,
            is_hidden: false,
            is_strikethrough: false,
        }
    }
}

// ---- colours ----

/// A colour is one specific type of ANSI escape code, and can refer
/// to either the foreground or background colour.
///
/// These use the standard numeric sequences.
/// See <http://invisible-island.net/xterm/ctlseqs/ctlseqs.html>
#[derive(PartialEq, Clone, Copy, Debug)]
#[cfg_attr(feature = "derive_serde_style", derive(serde::Deserialize, serde::Serialize))]
pub enum Colour {

    /// Colour #0 (foreground code `30`, background code `40`).
    ///
    /// This is not necessarily the background colour, and using it as one may
    /// render the text hard to read on terminals with dark backgrounds.
    Black,

    /// Colour #1 (foreground code `31`, background code `41`).
    Red,

    /// Colour #2 (foreground code `32`, background code `42`).
    Green,

    /// Colour #3 (foreground code `33`, background code `43`).
    Yellow,

    /// Colour #4 (foreground code `34`, background code `44`).
    Blue,

    /// Colour #5 (foreground code `35`, background code `45`).
    Purple,

    /// Colour #6 (foreground code `36`, background code `46`).
    Cyan,

    /// Colour #7 (foreground code `37`, background code `47`).
    ///
    /// As above, this is not necessarily the foreground colour, and may be
    /// hard to read on terminals with light backgrounds.
    White,

    /// A colour number from 0 to 255, for use in 256-colour terminal
    /// environments.
    ///
    /// - Colours 0 to 7 are the `Black` to `White` variants respectively.
    ///   These colours can usually be changed in the terminal emulator.
    /// - Colours 8 to 15 are brighter versions of the eight colours above.
    ///   These can also usually be changed in the terminal emulator, or it
    ///   could be configured to use the original colours and show the text in
    ///   bold instead. It varies depending on the program.
    /// - Colours 16 to 231 contain several palettes of bright colours,
    ///   arranged in six squares measuring six by six each.
    /// - Colours 232 to 255 are shades of grey from black to white.
    ///
    /// It might make more sense to look at a [colour chart][cc].
    ///
    /// [cc]: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg
    Fixed(u8),

    /// A 24-bit RGB color, as specified by ISO-8613-3.
    RGB(u8, u8, u8),
}

impl Colour {
    /// Return a `Style` with the foreground colour set to this colour.
    pub fn normal(self) -> Style {
        Style { foreground: Some(self), .. Style::default() }
    }

    /// Returns a `Style` with the bold property set.
    pub fn bold(self) -> Style {
        Style { foreground: Some(self), is_bold: true, .. Style::default() }
    }

    /// Returns a `Style` with the dimmed property set.
    pub fn dimmed(self) -> Style {
        Style { foreground: Some(self), is_dimmed: true, .. Style::default() }
    }

    /// Returns a `Style` with the italic property set.
    pub fn italic(self) -> Style {
        Style { foreground: Some(self), is_italic: true, .. Style::default() }
    }

    /// Returns a `Style` with the underline property set.
    pub fn underline(self) -> Style {
        Style { foreground: Some(self), is_underline: true, .. Style::default() }
    }

    /// Returns a `Style` with the blink property set.
    pub fn blink(self) -> Style {
        Style { foreground: Some(self), is_blink: true, .. Style::default() }
    }

    /// Returns a `Style` with the reverse property set.
    pub fn reverse(self) -> Style {
        Style { foreground: Some(self), is_reverse: true, .. Style::default() }
    }

    /// Returns a `Style` with the hidden property set.
    pub fn hidden(self) -> Style {
        Style { foreground: Some(self), is_hidden: true, .. Style::default() }
    }

    /// Returns a `Style` with the strikethrough property set.
    pub fn strikethrough(self) -> Style {
        Style { foreground: Some(self), is_strikethrough: true, .. Style::default() }
    }

    /// Returns a `Style` with the background colour property set.
    pub fn on(self, background: Colour) -> Style {
        Style { foreground: Some(self), background: Some(background), .. Style::default() }
    }
}

impl From<Colour> for Style {

    /// You can turn a `Colour` into a `Style` with the foreground colour set
    /// with the `From` trait.
    ///
    /// ```
    /// use ansi_term::{Style, Colour};
    /// let green_foreground = Style::default().fg(Colour::Green);
    /// assert_eq!(green_foreground, Colour::Green.normal());
    /// assert_eq!(green_foreground, Colour::Green.into());
    /// assert_eq!(green_foreground, Style::from(Colour::Green));
    /// ```
    fn from(colour: Colour) -> Style {
        colour.normal()
    }
}

#[cfg(test)]
#[cfg(feature = "derive_serde_style")]
mod serde_json_tests {
    use super::{Style, Colour};

    #[test]
    fn colour_serialization() {

        let colours = &[
            Colour::Red,
            Colour::Blue,
            Colour::RGB(123, 123, 123),
            Colour::Fixed(255),
        ];

        assert_eq!(serde_json::to_string(&colours).unwrap(), String::from("[\"Red\",\"Blue\",{\"RGB\":[123,123,123]},{\"Fixed\":255}]"));
    }

    #[test]
    fn colour_deserialization() {
        let colours = &[
            Colour::Red,
            Colour::Blue,
            Colour::RGB(123, 123, 123),
            Colour::Fixed(255),
        ];

        for colour in colours.into_iter() {
            let serialized = serde_json::to_string(&colour).unwrap();
            let deserialized: Colour = serde_json::from_str(&serialized).unwrap();

            assert_eq!(colour, &deserialized);
        }
    }

    #[test]
    fn style_serialization() {
        let style = Style::default();

        assert_eq!(serde_json::to_string(&style).unwrap(), "{\"foreground\":null,\"background\":null,\"is_bold\":false,\"is_dimmed\":false,\"is_italic\":false,\"is_underline\":false,\"is_blink\":false,\"is_reverse\":false,\"is_hidden\":false,\"is_strikethrough\":false}".to_string());
    }
}
<commit_msg>Add lots of “obvious” doctests<commit_after>/// A style is a collection of properties that can format a string
/// using ANSI escape codes.
#[derive(PartialEq, Clone, Copy)]
#[cfg_attr(feature = "derive_serde_style", derive(serde::Deserialize, serde::Serialize))]
pub struct Style {

    /// The style's foreground colour, if it has one.
    pub foreground: Option<Colour>,

    /// The style's background colour, if it has one.
    pub background: Option<Colour>,

    /// Whether this style is bold.
    pub is_bold: bool,

    /// Whether this style is dimmed.
    pub is_dimmed: bool,

    /// Whether this style is italic.
    pub is_italic: bool,

    /// Whether this style is underlined.
    pub is_underline: bool,

    /// Whether this style is blinking.
    pub is_blink: bool,

    /// Whether this style has reverse colours.
    pub is_reverse: bool,

    /// Whether this style is hidden.
    pub is_hidden: bool,

    /// Whether this style is struckthrough.
    pub is_strikethrough: bool
}

impl Style {

    /// Creates a new Style with no properties set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Style;
    ///
    /// let style = Style::new();
    /// println!("{}", style.paint("hi"));
    /// ```
    pub fn new() -> Style {
        Style::default()
    }

    /// Returns a `Style` with the bold property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Style;
    ///
    /// let style = Style::new().bold();
    /// println!("{}", style.paint("hey"));
    /// ```
    pub fn bold(&self) -> Style {
        Style { is_bold: true, .. *self }
    }

    /// Returns a `Style` with the dimmed property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Style;
    ///
    /// let style = Style::new().dimmed();
    /// println!("{}", style.paint("sup"));
    /// ```
    pub fn dimmed(&self) -> Style {
        Style { is_dimmed: true, .. *self }
    }

    /// Returns a `Style` with the italic property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Style;
    ///
    /// let style = Style::new().italic();
    /// println!("{}", style.paint("greetings"));
    /// ```
    pub fn italic(&self) -> Style {
        Style { is_italic: true, .. *self }
    }

    /// Returns a `Style` with the underline property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Style;
    ///
    /// let style = Style::new().underline();
    /// println!("{}", style.paint("salutations"));
    /// ```
    pub fn underline(&self) -> Style {
        Style { is_underline: true, .. *self }
    }

    /// Returns a `Style` with the blink property set.
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Style;
    ///
    /// let style = Style::new().blink();
    /// println!("{}", style.paint("wazzup"));
    /// ```
    pub fn blink(&self) -> Style {
        Style { is_blink: true, .. *self }
    }

    /// Returns a `Style` with the reverse property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Style;
    ///
    /// let style = Style::new().reverse();
    /// println!("{}", style.paint("aloha"));
    /// ```
    pub fn reverse(&self) -> Style {
        Style { is_reverse: true, .. *self }
    }

    /// Returns a `Style` with the hidden property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Style;
    ///
    /// let style = Style::new().hidden();
    /// println!("{}", style.paint("ahoy"));
    /// ```
    pub fn hidden(&self) -> Style {
        Style { is_hidden: true, .. *self }
    }

    /// Returns a `Style` with the strikethrough property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Style;
    ///
    /// let style = Style::new().strikethrough();
    /// println!("{}", style.paint("yo"));
    /// ```
    pub fn strikethrough(&self) -> Style {
        Style { is_strikethrough: true, .. *self }
    }

    /// Returns a `Style` with the foreground colour property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::{Style, Colour};
    ///
    /// let style = Style::new().fg(Colour::Yellow);
    /// println!("{}", style.paint("hi"));
    /// ```
    pub fn fg(&self, foreground: Colour) -> Style {
        Style { foreground: Some(foreground), .. *self }
    }

    /// Returns a `Style` with the background colour property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::{Style, Colour};
    ///
    /// let style = Style::new().on(Colour::Blue);
    /// println!("{}", style.paint("eyyyy"));
    /// ```
    pub fn on(&self, background: Colour) -> Style {
        Style { background: Some(background), .. *self }
    }

    /// Return true if this `Style` has no actual styles, and can be written
    /// without any control characters.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Style;
    ///
    /// assert_eq!(true,  Style::default().is_plain());
    /// assert_eq!(false, Style::default().bold().is_plain());
    /// ```
    pub fn is_plain(self) -> bool {
        self == Style::default()
    }
}

impl Default for Style {

    /// Returns a style with *no* properties set. Formatting text using this
    /// style returns the exact same text.
    ///
    /// ```
    /// use ansi_term::Style;
    /// assert_eq!(None,  Style::default().foreground);
    /// assert_eq!(None,  Style::default().background);
    /// assert_eq!(false, Style::default().is_bold);
    /// assert_eq!("txt", Style::default().paint("txt").to_string());
    /// ```
    fn default() -> Style {
        Style {
            foreground: None,
            background: None,
            is_bold: false,
            is_dimmed: false,
            is_italic: false,
            is_underline: false,
            is_blink: false,
            is_reverse: false,
            is_hidden: false,
            is_strikethrough: false,
        }
    }
}

// ---- colours ----

/// A colour is one specific type of ANSI escape code, and can refer
/// to either the foreground or background colour.
///
/// These use the standard numeric sequences.
/// See <http://invisible-island.net/xterm/ctlseqs/ctlseqs.html>
#[derive(PartialEq, Clone, Copy, Debug)]
#[cfg_attr(feature = "derive_serde_style", derive(serde::Deserialize, serde::Serialize))]
pub enum Colour {

    /// Colour #0 (foreground code `30`, background code `40`).
    ///
    /// This is not necessarily the background colour, and using it as one may
    /// render the text hard to read on terminals with dark backgrounds.
    Black,

    /// Colour #1 (foreground code `31`, background code `41`).
    Red,

    /// Colour #2 (foreground code `32`, background code `42`).
    Green,

    /// Colour #3 (foreground code `33`, background code `43`).
    Yellow,

    /// Colour #4 (foreground code `34`, background code `44`).
    Blue,

    /// Colour #5 (foreground code `35`, background code `45`).
    Purple,

    /// Colour #6 (foreground code `36`, background code `46`).
    Cyan,

    /// Colour #7 (foreground code `37`, background code `47`).
    ///
    /// As above, this is not necessarily the foreground colour, and may be
    /// hard to read on terminals with light backgrounds.
    White,

    /// A colour number from 0 to 255, for use in 256-colour terminal
    /// environments.
    ///
    /// - Colours 0 to 7 are the `Black` to `White` variants respectively.
    ///   These colours can usually be changed in the terminal emulator.
    /// - Colours 8 to 15 are brighter versions of the eight colours above.
    ///   These can also usually be changed in the terminal emulator, or it
    ///   could be configured to use the original colours and show the text in
    ///   bold instead. It varies depending on the program.
    /// - Colours 16 to 231 contain several palettes of bright colours,
    ///   arranged in six squares measuring six by six each.
    /// - Colours 232 to 255 are shades of grey from black to white.
    ///
    /// It might make more sense to look at a [colour chart][cc].
    ///
    /// [cc]: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg
    Fixed(u8),

    /// A 24-bit RGB color, as specified by ISO-8613-3.
    RGB(u8, u8, u8),
}

impl Colour {

    /// Returns a `Style` with the foreground colour set to this colour.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Colour;
    ///
    /// let style = Colour::Red.normal();
    /// println!("{}", style.paint("hi"));
    /// ```
    pub fn normal(self) -> Style {
        Style { foreground: Some(self), .. Style::default() }
    }

    /// Returns a `Style` with the foreground colour set to this colour and the
    /// bold property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Colour;
    ///
    /// let style = Colour::Green.bold();
    /// println!("{}", style.paint("hey"));
    /// ```
    pub fn bold(self) -> Style {
        Style { foreground: Some(self), is_bold: true, .. Style::default() }
    }

    /// Returns a `Style` with the foreground colour set to this colour and the
    /// dimmed property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Colour;
    ///
    /// let style = Colour::Yellow.dimmed();
    /// println!("{}", style.paint("sup"));
    /// ```
    pub fn dimmed(self) -> Style {
        Style { foreground: Some(self), is_dimmed: true, .. Style::default() }
    }

    /// Returns a `Style` with the foreground colour set to this colour and the
    /// italic property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Colour;
    ///
    /// let style = Colour::Blue.italic();
    /// println!("{}", style.paint("greetings"));
    /// ```
    pub fn italic(self) -> Style {
        Style { foreground: Some(self), is_italic: true, .. Style::default() }
    }

    /// Returns a `Style` with the foreground colour set to this colour and the
    /// underline property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Colour;
    ///
    /// let style = Colour::Purple.underline();
    /// println!("{}", style.paint("salutations"));
    /// ```
    pub fn underline(self) -> Style {
        Style { foreground: Some(self), is_underline: true, .. Style::default() }
    }

    /// Returns a `Style` with the foreground colour set to this colour and the
    /// blink property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Colour;
    ///
    /// let style = Colour::Cyan.blink();
    /// println!("{}", style.paint("wazzup"));
    /// ```
    pub fn blink(self) -> Style {
        Style { foreground: Some(self), is_blink: true, .. Style::default() }
    }

    /// Returns a `Style` with the foreground colour set to this colour and the
    /// reverse property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Colour;
    ///
    /// let style = Colour::Black.reverse();
    /// println!("{}", style.paint("aloha"));
    /// ```
    pub fn reverse(self) -> Style {
        Style { foreground: Some(self), is_reverse: true, .. Style::default() }
    }

    /// Returns a `Style` with the foreground colour set to this colour and the
    /// hidden property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Colour;
    ///
    /// let style = Colour::White.hidden();
    /// println!("{}", style.paint("ahoy"));
    /// ```
    pub fn hidden(self) -> Style {
        Style { foreground: Some(self), is_hidden: true, .. Style::default() }
    }

    /// Returns a `Style` with the foreground colour set to this colour and the
    /// strikethrough property set.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Colour;
    ///
    /// let style = Colour::Fixed(244).strikethrough();
    /// println!("{}", style.paint("yo"));
    /// ```
    pub fn strikethrough(self) -> Style {
        Style { foreground: Some(self), is_strikethrough: true, .. Style::default() }
    }

    /// Returns a `Style` with the foreground colour set to this colour and the
    /// background colour property set to the given colour.
    ///
    /// # Examples
    ///
    /// ```
    /// use ansi_term::Colour;
    ///
    /// let style = Colour::RGB(31, 31, 31).on(Colour::White);
    /// println!("{}", style.paint("eyyyy"));
    /// ```
    pub fn on(self, background: Colour) -> Style {
        Style { foreground: Some(self), background: Some(background), .. Style::default() }
    }
}

impl From<Colour> for Style {

    /// You can turn a `Colour` into a `Style` with the foreground colour set
    /// with the `From` trait.
    ///
    /// ```
    /// use ansi_term::{Style, Colour};
    /// let green_foreground = Style::default().fg(Colour::Green);
    /// assert_eq!(green_foreground, Colour::Green.normal());
    /// assert_eq!(green_foreground, Colour::Green.into());
    /// assert_eq!(green_foreground, Style::from(Colour::Green));
    /// ```
    fn from(colour: Colour) -> Style {
        colour.normal()
    }
}

#[cfg(test)]
#[cfg(feature = "derive_serde_style")]
mod serde_json_tests {
    use super::{Style, Colour};

    #[test]
    fn colour_serialization() {

        let colours = &[
            Colour::Red,
            Colour::Blue,
            Colour::RGB(123, 123, 123),
            Colour::Fixed(255),
        ];

        assert_eq!(serde_json::to_string(&colours).unwrap(), String::from("[\"Red\",\"Blue\",{\"RGB\":[123,123,123]},{\"Fixed\":255}]"));
    }

    #[test]
    fn colour_deserialization() {
        let colours = &[
            Colour::Red,
            Colour::Blue,
            Colour::RGB(123, 123, 123),
            Colour::Fixed(255),
        ];

        for colour in colours.into_iter() {
            let serialized = serde_json::to_string(&colour).unwrap();
            let deserialized: Colour = serde_json::from_str(&serialized).unwrap();

            assert_eq!(colour, &deserialized);
        }
    }

    #[test]
    fn style_serialization() {
        let style = Style::default();

        assert_eq!(serde_json::to_string(&style).unwrap(), "{\"foreground\":null,\"background\":null,\"is_bold\":false,\"is_dimmed\":false,\"is_italic\":false,\"is_underline\":false,\"is_blink\":false,\"is_reverse\":false,\"is_hidden\":false,\"is_strikethrough\":false}".to_string());
    }
}
<|endoftext|>


<commit_before>use std::slice::{Items, MutItems};
use std::vec::{Vec, MoveItems};

pub struct Table<T> {
    dimensions: (uint, uint),
    data: Vec<T>
}

impl<T: Clone> Table<T> {
    #[inline]
    pub fn from_elem(dimensions: (uint, uint), value: T) -> Table<T> {
        let (width, height) = dimensions;

        Table {
            dimensions: dimensions,
            data: Vec::from_elem(width * height, value)
        }
    }
}

impl<T> Table<T> {
    #[inline]
    fn get_vec_index(&self, index: (uint, uint)) -> uint {
        let (row, column) = index;
        let (width, height) = self.dimensions;

        if row >= height {
            panic!("Table::get_index: `row` overflow ({} >= {})", row, height)
        }
        if column >= width {
            panic!("Table::get_index: `column` overflow ({} >= {})", column, width)
        }

        row * width + column
    }

    #[inline]
    pub fn get_dimensions(&self) -> (uint, uint) {
        self.dimensions
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> TableItems<Items<'a, T>> {
        self.data.iter().as_table(self.dimensions)
    }

    #[inline]
    pub fn iter_mut<'a>(&'a mut self) -> TableItems<MutItems<'a, T>> {
        self.data.iter_mut().as_table(self.dimensions)
    }

    #[inline]
    pub fn into_iter<'a>(self) -> TableItems<MoveItems<T>> {
        self.data.into_iter().as_table(self.dimensions)
    }
}

impl<T> Index<(uint, uint), T> for Table<T> {
    #[inline]
    fn index<'a>(&'a self, index: &(uint, uint)) -> &'a T {
        let vec_index = self.get_vec_index(*index);
        self.data.index(&vec_index)
    }
}

impl<T> IndexMut<(uint, uint), T> for Table<T> {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: &(uint, uint)) -> &'a mut T {
        let vec_index = self.get_vec_index(*index);
        self.data.index_mut(&vec_index)
    }
}

pub struct TableItems<T> {
    iter: T,
    dimensions: (uint, uint)
}

impl<A, T: Iterator<A>> Iterator<A> for TableItems<T> {
    #[inline]
    fn next(&mut self) -> Option<A> {
        self.iter.next()
    }
}

pub trait AsTable<'a, T> {
    #[inline]
    fn as_table(self, dimensions: (uint, uint)) -> TableItems<Self> {
        TableItems {
            iter: self,
            dimensions: dimensions
        }
    }
}

impl<'a, A, T: Iterator<A>> AsTable<'a, T> for T {}

pub struct TableEnumerate<T> {
    iter: T,
    row_count: uint,
    column_count: uint
}

impl<A, T: Iterator<A>> Iterator<((uint, uint), A)> for TableEnumerate<TableItems<T>> {
    #[inline]
    fn next(&mut self) -> Option<((uint, uint), A)> {
        let (width, _) = self.iter.dimensions;

        match self.iter.next() {
            Some(value) => {
                let ret = Some(((self.row_count, self.column_count), value));

                self.column_count += 1;
                if self.column_count == width {
                    self.row_count += 1;
                    self.column_count = 0;
                }
                ret
            },
            None => None
        }
    }

    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        self.iter.size_hint()
    }
}

impl<T> TableItems<T> {
    #[inline]
    pub fn enumerate_2d(self) -> TableEnumerate<TableItems<T>> {
        TableEnumerate {
            iter: self,
            row_count: 0,
            column_count: 0
        }
    }

    #[inline]
    pub fn enumerate_2d_from(self, start: (uint, uint)) -> TableEnumerate<TableItems<T>> {
        let (row_start, column_start) = start;

        TableEnumerate {
            iter: self,
            row_count: row_start,
            column_count: column_start
        }
    }

    #[inline]
    pub fn enumerate_2d_from_index(self, index: uint) -> TableEnumerate<TableItems<T>> {
        let (width, _) = self.dimensions;
        let row_start = index / width;
        let column_start = index % width;

        TableEnumerate {
            iter: self,
            row_count: row_start,
            column_count: column_start
        }
    }
}
<commit_msg>Update the names of the iterators to match the standard.<commit_after>use std::slice::{Iter, IterMut};
use std::vec::{Vec, IntoIter};

pub struct Table<T> {
    dimensions: (uint, uint),
    data: Vec<T>
}

impl<T: Clone> Table<T> {
    #[inline]
    pub fn from_elem(dimensions: (uint, uint), value: T) -> Table<T> {
        let (width, height) = dimensions;

        Table {
            dimensions: dimensions,
            data: Vec::from_elem(width * height, value)
        }
    }
}

impl<T> Table<T> {
    #[inline]
    fn get_vec_index(&self, index: (uint, uint)) -> uint {
        let (row, column) = index;
        let (width, height) = self.dimensions;

        if row >= height {
            panic!("Table::get_index: `row` overflow ({} >= {})", row, height)
        }
        if column >= width {
            panic!("Table::get_index: `column` overflow ({} >= {})", column, width)
        }

        row * width + column
    }

    #[inline]
    pub fn get_dimensions(&self) -> (uint, uint) {
        self.dimensions
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> TableIter<Iter<'a, T>> {
        self.data.iter().as_table(self.dimensions)
    }

    #[inline]
    pub fn iter_mut<'a>(&'a mut self) -> TableIter<IterMut<'a, T>> {
        self.data.iter_mut().as_table(self.dimensions)
    }

    #[inline]
    pub fn into_iter<'a>(self) -> TableIter<IntoIter<T>> {
        self.data.into_iter().as_table(self.dimensions)
    }
}

impl<T> Index<(uint, uint), T> for Table<T> {
    #[inline]
    fn index<'a>(&'a self, index: &(uint, uint)) -> &'a T {
        let vec_index = self.get_vec_index(*index);
        self.data.index(&vec_index)
    }
}

impl<T> IndexMut<(uint, uint), T> for Table<T> {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: &(uint, uint)) -> &'a mut T {
        let vec_index = self.get_vec_index(*index);
        self.data.index_mut(&vec_index)
    }
}

pub struct TableIter<T> {
    iter: T,
    dimensions: (uint, uint)
}

impl<A, T: Iterator<A>> Iterator<A> for TableIter<T> {
    #[inline]
    fn next(&mut self) -> Option<A> {
        self.iter.next()
    }
}

pub trait AsTable<'a, T> {
    #[inline]
    fn as_table(self, dimensions: (uint, uint)) -> TableIter<Self> {
        TableIter {
            iter: self,
            dimensions: dimensions
        }
    }
}

impl<'a, A, T: Iterator<A>> AsTable<'a, T> for T {}

pub struct TableEnumerate<T> {
    iter: T,
    row_count: uint,
    column_count: uint
}

impl<A, T: Iterator<A>> Iterator<((uint, uint), A)> for TableEnumerate<TableIter<T>> {
    #[inline]
    fn next(&mut self) -> Option<((uint, uint), A)> {
        let (width, _) = self.iter.dimensions;

        match self.iter.next() {
            Some(value) => {
                let ret = Some(((self.row_count, self.column_count), value));

                self.column_count += 1;
                if self.column_count == width {
                    self.row_count += 1;
                    self.column_count = 0;
                }
                ret
            },
            None => None
        }
    }

    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        self.iter.size_hint()
    }
}

impl<T> TableIter<T> {
    #[inline]
    pub fn enumerate_2d(self) -> TableEnumerate<TableIter<T>> {
        TableEnumerate {
            iter: self,
            row_count: 0,
            column_count: 0
        }
    }

    #[inline]
    pub fn enumerate_2d_from(self, start: (uint, uint)) -> TableEnumerate<TableIter<T>> {
        let (row_start, column_start) = start;

        TableEnumerate {
            iter: self,
            row_count: row_start,
            column_count: column_start
        }
    }

    #[inline]
    pub fn enumerate_2d_from_index(self, index: uint) -> TableEnumerate<TableIter<T>> {
        let (width, _) = self.dimensions;
        let row_start = index / width;
        let column_start = index % width;

        TableEnumerate {
            iter: self,
            row_count: row_start,
            column_count: column_start
        }
    }
}
<|endoftext|>


<commit_before>//! Module for parsing ISO Base Media Format aka video/mp4 streams.
//! Internal unit tests.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::io::Cursor;
use super::*;
extern crate test_assembler;
use self::test_assembler::*;

enum BoxSize {
    Short(u32),
    Long(u64),
    UncheckedShort(u32),
    UncheckedLong(u64),
}

fn make_box_raw<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    let mut section = Section::new();
    section = match size {
        BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
        BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
    };
    section = section.append_bytes(name);
    section = match size {
        // The spec allows the 32-bit size to be 0 to indicate unknown
        // length streams.  It's not clear if this is valid when using a
        // 64-bit size, so prohibit it for now.
        BoxSize::Long(size) => {
            assert!(size > 0);
            section.B64(size)
        }
        BoxSize::UncheckedLong(size) => section.B64(size),
        _ => section,
    };
    section = func(section);
    match size {
        BoxSize::Short(size) => {
            if size > 0 {
                assert_eq!(size as u64, section.size())
            }
        }
        BoxSize::Long(size) => assert_eq!(size, section.size()),
        _ => (),
    }
    Cursor::new(section.get_contents().unwrap())
}

fn make_box<F>(size: u32, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, func)
}

fn make_fullbox<F>(size: u32, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, |s| {
        func(s.B8(version)
              .B8(0)
              .B8(0)
              .B8(0))
    })
}

#[test]
fn read_box_header_short() {
    let mut stream = make_box_raw(BoxSize::Short(8), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 8);
}

#[test]
fn read_box_header_long() {
    let mut stream = make_box_raw(BoxSize::Long(16), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 16);
}

#[test]
fn read_box_header_short_unknown_size() {
    let mut stream = make_box_raw(BoxSize::Short(0), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::Unsupported) => (),
        _ => panic!("unexpected result reading box with unknown size"),
    };
}

#[test]
fn read_box_header_short_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedShort(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_box_header_long_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedLong(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_ftyp() {
    let mut stream = make_box(24, b"ftyp", |s| {
        s.append_bytes(b"mp42")
         .B32(0) // minor version
         .append_bytes(b"isom")
         .append_bytes(b"mp42")
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"ftyp"));
    assert_eq!(parsed.header.size, 24);
    assert_eq!(parsed.major_brand, FourCC(*b"mp42"));
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    assert_eq!(parsed.compatible_brands[0], FourCC(*b"isom"));
    assert_eq!(parsed.compatible_brands[1], FourCC(*b"mp42"));
}

#[test]
#[should_panic(expected = "expected an error result")]
fn read_truncated_ftyp() {
    // We declare a 24 byte box, but only write 20 bytes.
    let mut stream = make_box_raw(BoxSize::UncheckedShort(24), b"ftyp", |s| {
        s.append_bytes(b"mp42")
            .B32(0) // minor version
            .append_bytes(b"isom")
    });
    let mut context = MediaContext::new();
    context.trace(true);
    match read_mp4(&mut stream, &mut context) {
        Err(Error::UnexpectedEOF) => (),
        Ok(_) => assert!(false, "expected an error result"),
        _ => assert!(false, "expected a different error result"),
    }
}

#[test]
fn read_elst_v0() {
    let mut stream = make_fullbox(28, b"elst", 0, |s| {
        s.B32(1) // list count
          // first entry
         .B32(1234) // duration
         .B32(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 28);
    assert_eq!(parsed.edits.len(), 1);
    assert_eq!(parsed.edits[0].segment_duration, 1234);
    assert_eq!(parsed.edits[0].media_time, 5678);
    assert_eq!(parsed.edits[0].media_rate_integer, 12);
    assert_eq!(parsed.edits[0].media_rate_fraction, 34);
}

#[test]
fn read_elst_v1() {
    let mut stream = make_fullbox(56, b"elst", 1, |s| {
        s.B32(2) // list count
         // first entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
         // second entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 56);
    assert_eq!(parsed.edits.len(), 2);
    assert_eq!(parsed.edits[1].segment_duration, 1234);
    assert_eq!(parsed.edits[1].media_time, 5678);
    assert_eq!(parsed.edits[1].media_rate_integer, 12);
    assert_eq!(parsed.edits[1].media_rate_fraction, 34);
}

#[test]
fn read_mdhd_v0() {
    let mut stream = make_fullbox(32, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_v1() {
    let mut stream = make_fullbox(44, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 44);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_unknown_duration() {
    let mut stream = make_fullbox(32, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(::std::u32::MAX) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_mdhd_invalid_timescale() {
    let mut stream = make_fullbox(44, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mdhd(&mut stream, &header, &mut super::Track::new(0));
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_v0() {
    let mut stream = make_fullbox(108, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_v1() {
    let mut stream = make_fullbox(120, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 120);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_invalid_timescale() {
    let mut stream = make_fullbox(120, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mvhd(&mut stream, &header);
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_unknown_duration() {
    let mut stream = make_fullbox(108, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(::std::u32::MAX)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}
<commit_msg>Remove left over tracing from read_truncated_ftyp.<commit_after>//! Module for parsing ISO Base Media Format aka video/mp4 streams.
//! Internal unit tests.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::io::Cursor;
use super::*;
extern crate test_assembler;
use self::test_assembler::*;

enum BoxSize {
    Short(u32),
    Long(u64),
    UncheckedShort(u32),
    UncheckedLong(u64),
}

fn make_box_raw<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    let mut section = Section::new();
    section = match size {
        BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
        BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
    };
    section = section.append_bytes(name);
    section = match size {
        // The spec allows the 32-bit size to be 0 to indicate unknown
        // length streams.  It's not clear if this is valid when using a
        // 64-bit size, so prohibit it for now.
        BoxSize::Long(size) => {
            assert!(size > 0);
            section.B64(size)
        }
        BoxSize::UncheckedLong(size) => section.B64(size),
        _ => section,
    };
    section = func(section);
    match size {
        BoxSize::Short(size) => {
            if size > 0 {
                assert_eq!(size as u64, section.size())
            }
        }
        BoxSize::Long(size) => assert_eq!(size, section.size()),
        _ => (),
    }
    Cursor::new(section.get_contents().unwrap())
}

fn make_box<F>(size: u32, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, func)
}

fn make_fullbox<F>(size: u32, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, |s| {
        func(s.B8(version)
              .B8(0)
              .B8(0)
              .B8(0))
    })
}

#[test]
fn read_box_header_short() {
    let mut stream = make_box_raw(BoxSize::Short(8), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 8);
}

#[test]
fn read_box_header_long() {
    let mut stream = make_box_raw(BoxSize::Long(16), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 16);
}

#[test]
fn read_box_header_short_unknown_size() {
    let mut stream = make_box_raw(BoxSize::Short(0), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::Unsupported) => (),
        _ => panic!("unexpected result reading box with unknown size"),
    };
}

#[test]
fn read_box_header_short_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedShort(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_box_header_long_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedLong(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_ftyp() {
    let mut stream = make_box(24, b"ftyp", |s| {
        s.append_bytes(b"mp42")
         .B32(0) // minor version
         .append_bytes(b"isom")
         .append_bytes(b"mp42")
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"ftyp"));
    assert_eq!(parsed.header.size, 24);
    assert_eq!(parsed.major_brand, FourCC(*b"mp42"));
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    assert_eq!(parsed.compatible_brands[0], FourCC(*b"isom"));
    assert_eq!(parsed.compatible_brands[1], FourCC(*b"mp42"));
}

#[test]
#[should_panic(expected = "expected an error result")]
fn read_truncated_ftyp() {
    // We declare a 24 byte box, but only write 20 bytes.
    let mut stream = make_box_raw(BoxSize::UncheckedShort(24), b"ftyp", |s| {
        s.append_bytes(b"mp42")
            .B32(0) // minor version
            .append_bytes(b"isom")
    });
    let mut context = MediaContext::new();
    match read_mp4(&mut stream, &mut context) {
        Err(Error::UnexpectedEOF) => (),
        Ok(_) => assert!(false, "expected an error result"),
        _ => assert!(false, "expected a different error result"),
    }
}

#[test]
fn read_elst_v0() {
    let mut stream = make_fullbox(28, b"elst", 0, |s| {
        s.B32(1) // list count
          // first entry
         .B32(1234) // duration
         .B32(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 28);
    assert_eq!(parsed.edits.len(), 1);
    assert_eq!(parsed.edits[0].segment_duration, 1234);
    assert_eq!(parsed.edits[0].media_time, 5678);
    assert_eq!(parsed.edits[0].media_rate_integer, 12);
    assert_eq!(parsed.edits[0].media_rate_fraction, 34);
}

#[test]
fn read_elst_v1() {
    let mut stream = make_fullbox(56, b"elst", 1, |s| {
        s.B32(2) // list count
         // first entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
         // second entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 56);
    assert_eq!(parsed.edits.len(), 2);
    assert_eq!(parsed.edits[1].segment_duration, 1234);
    assert_eq!(parsed.edits[1].media_time, 5678);
    assert_eq!(parsed.edits[1].media_rate_integer, 12);
    assert_eq!(parsed.edits[1].media_rate_fraction, 34);
}

#[test]
fn read_mdhd_v0() {
    let mut stream = make_fullbox(32, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_v1() {
    let mut stream = make_fullbox(44, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 44);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_unknown_duration() {
    let mut stream = make_fullbox(32, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(::std::u32::MAX) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_mdhd_invalid_timescale() {
    let mut stream = make_fullbox(44, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mdhd(&mut stream, &header, &mut super::Track::new(0));
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_v0() {
    let mut stream = make_fullbox(108, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_v1() {
    let mut stream = make_fullbox(120, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 120);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_invalid_timescale() {
    let mut stream = make_fullbox(120, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mvhd(&mut stream, &header);
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_unknown_duration() {
    let mut stream = make_fullbox(108, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(::std::u32::MAX)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}
<|endoftext|>


<commit_before>use core::mem;
use core::cell::Cell;
use syscalls::{self, command, yieldk_for};

const TIMER: u32 = 0;
const GET_CLOCK_FREQUENCY: u32 = 1;
const SET_ALARM_NOTIFICATION: u32 = 4;
const GET_CLOCK_VALUE: u32 = 2;

pub unsafe fn subscribe(cb: extern fn(usize, usize, usize, usize), ud: usize) {
    syscalls::subscribe(3, 0, cb, ud);
}

pub fn start_oneshot(ms: u32) {
    unsafe {
        command(TIMER, SET_ALARM_NOTIFICATION, ms as isize);
    }
}

pub fn start_repeating(ms: u32) {
    unsafe {
        command(TIMER, 2, ms as isize);
    }
}

pub fn stop(ms: u32) {
    unsafe {
        command(TIMER, 3, ms as isize);
    }
}

pub fn delay_ms(ms: u32) {
    extern fn cb(_: usize, _: usize, _: usize, expired_ptr: usize) {
        let expired: &Cell<bool> = unsafe {
            mem::transmute(expired_ptr)
        };
        expired.set(true);
    }

    let f: u32 = unsafe { command(TIMER, GET_CLOCK_FREQUENCY, 0) as u32 };
    let point: u32 = unsafe { command(TIMER, GET_CLOCK_VALUE, 0) as u32 } + ms * f / 1000;

    let expired = Cell::new(false);
    unsafe {
        subscribe(cb, &expired as *const _ as usize);
        start_oneshot(point);
        yieldk_for(|| expired.get() );
    }
}

<commit_msg>Refactoring<commit_after>use core::mem;
use core::cell::Cell;
use syscalls::{self, command, yieldk_for};

const DRIVER_NUMBER: u32 = 0;
const GET_CLOCK_FREQUENCY: u32 = 1;
const SET_ALARM_NOTIFICATION: u32 = 4;
const GET_CLOCK_VALUE: u32 = 2;

pub unsafe fn subscribe(cb: extern fn(usize, usize, usize, usize), ud: usize) {
    syscalls::subscribe(3, 0, cb, ud);
}

pub fn start_oneshot(ms: u32) {
    unsafe {
        command(DRIVER_NUMBER, SET_ALARM_NOTIFICATION, ms as isize);
    }
}

pub fn start_repeating(ms: u32) {
    unsafe {
        command(DRIVER_NUMBER, 2, ms as isize);
    }
}

pub fn stop(ms: u32) {
    unsafe {
        command(DRIVER_NUMBER, 3, ms as isize);
    }
}

pub fn delay_ms(ms: u32) {
    extern fn cb(_: usize, _: usize, _: usize, expired_ptr: usize) {
        let expired: &Cell<bool> = unsafe {
            mem::transmute(expired_ptr)
        };
        expired.set(true);
    }

    let f: u32 = unsafe { command(DRIVER_NUMBER, GET_CLOCK_FREQUENCY, 0) as u32 };
    let point: u32 = unsafe { command(DRIVER_NUMBER, GET_CLOCK_VALUE, 0) as u32 } + ms * f / 1000;

    let expired = Cell::new(false);
    unsafe {
        subscribe(cb, &expired as *const _ as usize);
        start_oneshot(point);
        yieldk_for(|| expired.get() );
    }
}

<|endoftext|>


<commit_before>//! Time utitities
use std::error::Error;
use std::cmp::max;
use rotor::{Machine, Scope, Response, EventSet, GenericScope};
use void::{Void, unreachable};

use {Duration, Deadline};

/// Ticker state machine
///
/// The structure implements `rotor::Machine` but exposes a simpler protocol
/// that has just one method which is called when timer expires.
///
/// The `Ticker` machine also ensures that there are no spurious events.
pub struct Ticker<M: Timer> {
    deadline: Deadline,
    machine: M,
}

/// Interval state machine
///
/// It's the state machine used for ticker that wakes up with fixed intervals
pub struct Interval<M: SimpleTimer>(Duration, M);

/// A convenience type for declaring state machines
pub type IntervalFunc<C> = Ticker<Interval<Box<FnMut(&mut Scope<C>)>>>;

/// A protocol for the state machine that put into the `Ticker`
pub trait Timer {
    type Context;

    /// Called when time elapsed
    fn timeout(self, scope: &mut Scope<Self::Context>) -> Self;

    /// Calculates the next wakeup time
    ///
    /// `now` -- is time when event processing was started, this is provided
    ///          for performance reasons
    /// `scheduled` -- time when event had to occur
    ///
    /// There are two options to calculate the time. If you just need to
    /// run something on occasion use simply:
    /// ```ignore
    /// now + Duration::seconds(interval)
    /// ```
    ///
    /// Or if you need to run strict number of times and as close as possible
    /// to the multiple of the interval time. You may want:
    /// ```ignore
    /// scheduled + Duration::seconds(interval)
    /// ```
    ///
    /// Note, in both cases mio will run timeout handler on the next tick
    /// of the timer, which means +200 ms by default.
    fn next_wakeup_time(&self, now: Deadline, scheduled: Deadline,
        scope: &mut Scope<Self::Context>)
        -> Deadline;
}

/// The timer trait used in the `Ticker<Interval<T>>`
pub trait SimpleTimer {
    type Context;

    /// Called when time elapsed
    fn timeout(self, scope: &mut Scope<Self::Context>) -> Self;
}

impl<T: Timer> Ticker<T> {
    pub fn new(scope: &mut Scope<T::Context>, machine: T) -> Ticker<T> {
        let now = Deadline::now();
        let next = machine.next_wakeup_time(now, now, scope);
        scope.timeout_ms(
            max(0, (next - now).num_milliseconds()) as u64).unwrap();
        Ticker {
            deadline: next,
            machine: machine,
        }
    }
}

impl<M: Timer> Machine for Ticker<M> {
    type Context = M::Context;
    type Seed = Void;
    fn create(seed: Self::Seed, _scope: &mut Scope<Self::Context>)
        -> Result<Self, Box<Error>>
    {
        unreachable(seed);
    }
    fn ready(self, _events: EventSet, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        // Spurious event
        Response::ok(self)
    }
    fn spawned(self, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        let now = Deadline::now();
        if now > self.deadline {
            let newm = self.machine.timeout(scope);
            let next = newm.next_wakeup_time(now, self.deadline, scope);
            scope.timeout_ms(
                max(0, (next - now).num_milliseconds()) as u64).unwrap();
            Response::ok(Ticker {
                deadline: next,
                machine: newm,
            })
        } else {
            Response::ok(self)
        }
    }
    fn wakeup(self, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        // Spurious wakeup
        Response::ok(self)
    }
}

impl<T: SimpleTimer> Timer for Interval<T> {
    type Context = T::Context;
    fn timeout(self, scope: &mut Scope<Self::Context>) -> Self {
        Interval(self.0, self.1.timeout(scope))
    }
    fn next_wakeup_time(&self, now: Deadline, scheduled: Deadline,
        _scope: &mut Scope<Self::Context>)
        -> Deadline
    {
        // Try to minimize the drift
        let goal = scheduled + self.0;
        if now > goal {
            // But if we are a way too late, just use current time
            return now + self.0;
        } else {
            return goal;
        }
    }
}

impl<C> SimpleTimer for Box<FnMut(&mut Scope<C>)> {
    type Context = C;
    fn timeout(mut self, scope: &mut Scope<Self::Context>) -> Self {
        self(scope);
        self
    }
}

/// A helper function to create intervals from closures
pub fn interval_func<C, F>(scope: &mut Scope<C>, interval: Duration, fun: F)
    -> IntervalFunc<C>
    where F: FnMut(&mut Scope<C>) + 'static
{
    Ticker::new(scope, Interval(interval, Box::new(fun)))
}
<commit_msg>Require Send on an IntervalFunc parameter (by default)<commit_after>//! Time utitities
use std::error::Error;
use std::cmp::max;
use rotor::{Machine, Scope, Response, EventSet, GenericScope};
use void::{Void, unreachable};

use {Duration, Deadline};

/// Ticker state machine
///
/// The structure implements `rotor::Machine` but exposes a simpler protocol
/// that has just one method which is called when timer expires.
///
/// The `Ticker` machine also ensures that there are no spurious events.
pub struct Ticker<M: Timer> {
    deadline: Deadline,
    machine: M,
}

/// Interval state machine
///
/// It's the state machine used for ticker that wakes up with fixed intervals
pub struct Interval<M: SimpleTimer>(Duration, M);

/// A convenience type for declaring state machines
pub type IntervalFunc<C> = Ticker<Interval<Box<FnMut(&mut Scope<C>) + Send>>>;

/// A protocol for the state machine that put into the `Ticker`
pub trait Timer {
    type Context;

    /// Called when time elapsed
    fn timeout(self, scope: &mut Scope<Self::Context>) -> Self;

    /// Calculates the next wakeup time
    ///
    /// `now` -- is time when event processing was started, this is provided
    ///          for performance reasons
    /// `scheduled` -- time when event had to occur
    ///
    /// There are two options to calculate the time. If you just need to
    /// run something on occasion use simply:
    /// ```ignore
    /// now + Duration::seconds(interval)
    /// ```
    ///
    /// Or if you need to run strict number of times and as close as possible
    /// to the multiple of the interval time. You may want:
    /// ```ignore
    /// scheduled + Duration::seconds(interval)
    /// ```
    ///
    /// Note, in both cases mio will run timeout handler on the next tick
    /// of the timer, which means +200 ms by default.
    fn next_wakeup_time(&self, now: Deadline, scheduled: Deadline,
        scope: &mut Scope<Self::Context>)
        -> Deadline;
}

/// The timer trait used in the `Ticker<Interval<T>>`
pub trait SimpleTimer {
    type Context;

    /// Called when time elapsed
    fn timeout(self, scope: &mut Scope<Self::Context>) -> Self;
}

impl<T: Timer> Ticker<T> {
    pub fn new(scope: &mut Scope<T::Context>, machine: T) -> Ticker<T> {
        let now = Deadline::now();
        let next = machine.next_wakeup_time(now, now, scope);
        scope.timeout_ms(
            max(0, (next - now).num_milliseconds()) as u64).unwrap();
        Ticker {
            deadline: next,
            machine: machine,
        }
    }
}

impl<M: Timer> Machine for Ticker<M> {
    type Context = M::Context;
    type Seed = Void;
    fn create(seed: Self::Seed, _scope: &mut Scope<Self::Context>)
        -> Result<Self, Box<Error>>
    {
        unreachable(seed);
    }
    fn ready(self, _events: EventSet, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        // Spurious event
        Response::ok(self)
    }
    fn spawned(self, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        let now = Deadline::now();
        if now > self.deadline {
            let newm = self.machine.timeout(scope);
            let next = newm.next_wakeup_time(now, self.deadline, scope);
            scope.timeout_ms(
                max(0, (next - now).num_milliseconds()) as u64).unwrap();
            Response::ok(Ticker {
                deadline: next,
                machine: newm,
            })
        } else {
            Response::ok(self)
        }
    }
    fn wakeup(self, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        // Spurious wakeup
        Response::ok(self)
    }
}

impl<T: SimpleTimer> Timer for Interval<T> {
    type Context = T::Context;
    fn timeout(self, scope: &mut Scope<Self::Context>) -> Self {
        Interval(self.0, self.1.timeout(scope))
    }
    fn next_wakeup_time(&self, now: Deadline, scheduled: Deadline,
        _scope: &mut Scope<Self::Context>)
        -> Deadline
    {
        // Try to minimize the drift
        let goal = scheduled + self.0;
        if now > goal {
            // But if we are a way too late, just use current time
            return now + self.0;
        } else {
            return goal;
        }
    }
}

impl<C> SimpleTimer for Box<FnMut(&mut Scope<C>) + Send> {
    type Context = C;
    fn timeout(mut self, scope: &mut Scope<Self::Context>) -> Self {
        self(scope);
        self
    }
}

/// A helper function to create intervals from closures
pub fn interval_func<C, F>(scope: &mut Scope<C>, interval: Duration, fun: F)
    -> IntervalFunc<C>
    where F: FnMut(&mut Scope<C>) + 'static + Send
{
    Ticker::new(scope, Interval(interval, Box::new(fun)))
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use syntax::ast;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::ptr::P;
use rustc::middle::ty;
use syntax::codemap::ExpnInfo;

use utils::{in_macro, snippet, span_lint, span_help_and_lint, in_external_macro};

/// Handles all the linting of funky types
#[allow(missing_copy_implementations)]
pub struct TypePass;

declare_lint!(pub BOX_VEC, Warn,
              "usage of `Box<Vec<T>>`, vector elements are already on the heap");
declare_lint!(pub LINKEDLIST, Warn,
              "usage of LinkedList, usually a vector is faster, or a more specialized data \
               structure like a RingBuf");

/// Matches a type with a provided string, and returns its type parameters if successful
pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
    match ty.node {
        TyPath(_, Path {segments: ref seg, ..}) => {
            // So ast::Path isn't the full path, just the tokens that were provided.
            // I could muck around with the maps and find the full path
            // however the more efficient way is to simply reverse the iterators and zip them
            // which will compare them in reverse until one of them runs out of segments
            if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.name == b) {
                match seg[..].last() {
                    Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => {
                        Some(&a.types[..])
                    }
                    _ => None
                }
            } else {
                None
            }
        },
        _ => None
    }
}

#[allow(unused_imports)]
impl LintPass for TypePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(BOX_VEC, LINKEDLIST)
    }

    fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) {
        {
            // In case stuff gets moved around
            use std::boxed::Box;
            use std::vec::Vec;
        }
        match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first())
          .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"]))
          .map(|_| {
            span_help_and_lint(cx, BOX_VEC, ty.span,
                              "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?",
                              "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation");
          });
        {
            // In case stuff gets moved around
            use collections::linked_list::LinkedList as DL1;
            use std::collections::linked_list::LinkedList as DL2;
        }
        let dlists = [vec!["std","collections","linked_list","LinkedList"],
                      vec!["collections","linked_list","LinkedList"]];
        for path in &dlists {
            if match_ty_unwrap(ty, &path[..]).is_some() {
                span_help_and_lint(cx, LINKEDLIST, ty.span,
                                   "I see you're using a LinkedList! Perhaps you meant some other data structure?",
                                   "a RingBuf might work");
                return;
            }
        }
    }
}

#[allow(missing_copy_implementations)]
pub struct LetPass;

declare_lint!(pub LET_UNIT_VALUE, Warn,
              "creating a let binding to a value of unit type, which usually can't be used afterwards");

fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) {
    if in_macro(cx, info) { return; }
    if let DeclLocal(ref local) = decl.node {
        let bindtype = &cx.tcx.pat_ty(&*local.pat).sty;
        if *bindtype == ty::TyTuple(vec![]) {
            span_lint(cx, LET_UNIT_VALUE, decl.span, &format!(
                "this let-binding has unit value. Consider omitting `let {} =`",
                snippet(cx, local.pat.span, "..")));
        }
    }
}

impl LintPass for LetPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(LET_UNIT_VALUE)
    }

    fn check_decl(&mut self, cx: &Context, decl: &Decl) {
        cx.sess().codemap().with_expn_info(
            decl.span.expn_id,
            |info| check_let_unit(cx, decl, info));
    }
}

declare_lint!(pub UNIT_CMP, Warn,
              "comparing unit values (which is always `true` or `false`, respectively)");

#[allow(missing_copy_implementations)]
pub struct UnitCmp;

impl LintPass for UnitCmp {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNIT_CMP)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprBinary(ref cmp, ref left, _) = expr.node {
            let op = cmp.node;
            let sty = &cx.tcx.expr_ty(left).sty;
            if *sty == ty::TyTuple(vec![]) && is_comparison_binop(op) {
                let result = match op {
                    BiEq | BiLe | BiGe => "true",
                    _ => "false"
                };
                span_lint(cx, UNIT_CMP, expr.span, &format!(
                    "{}-comparison of unit values detected. This will always be {}",
                    binop_to_string(op), result));
            }
        }
    }
}

pub struct CastPass;

declare_lint!(pub CAST_PRECISION_LOSS, Allow,
              "casts that cause loss of precision, e.g `x as f32` where `x: u64`");
declare_lint!(pub CAST_SIGN_LOSS, Allow,
              "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`");
declare_lint!(pub CAST_POSSIBLE_OVERFLOW, Allow,
              "casts that may cause overflow, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`");

impl LintPass for CastPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(CAST_PRECISION_LOSS,
                    CAST_SIGN_LOSS,
                    CAST_POSSIBLE_OVERFLOW)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprCast(ref ex, _) = expr.node {
            let (cast_from, cast_to) = (cx.tcx.expr_ty(&*ex), cx.tcx.expr_ty(expr));
            if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) {
                match (cast_from.is_integral(), cast_to.is_integral()) {
                    (true, false)  => {
                        match (&cast_from.sty, &cast_to.sty) {
                            (&ty::TyInt(i), &ty::TyFloat(f)) => {
                                match (i, f) {
                                    (ast::TyI32, ast::TyF32) |
                                    (ast::TyI64, ast::TyF32) |
                                    (ast::TyI64, ast::TyF64) => {
                                        span_lint(cx, CAST_PRECISION_LOSS, expr.span,
                                                  &format!("converting from {} to {}, which causes a loss of precision",
                                                           i, f));
                                    },
                                    _ => ()
                                }
                            }
                            (&ty::TyUint(u), &ty::TyFloat(f)) => {
                                match (u, f) {
                                    (ast::TyU32, ast::TyF32) |
                                    (ast::TyU64, ast::TyF32) |
                                    (ast::TyU64, ast::TyF64) => {
                                        span_lint(cx, CAST_PRECISION_LOSS, expr.span,
                                                  &format!("converting from {} to {}, which causes a loss of precision",
                                                           u, f));
                                    },
                                    _ => ()
                                }
                            },
                            _ => ()
                        }
                    },
                    (false, true) => {
                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                  &format!("the contents of a {} may overflow a {}", cast_from, cast_to));
                        if !cx.tcx.expr_ty(expr).is_signed() {
                            span_lint(cx, CAST_SIGN_LOSS, expr.span,
                                      &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to));
                        }
                    },
                    (true, true) => {
                        match (&cast_from.sty, &cast_to.sty) {
                            (&ty::TyInt(i1), &ty::TyInt(i2)) => {
                                match (i1, i2) {
                                    (ast::TyI64, ast::TyI32) |
                                    (ast::TyI64, ast::TyI16) |
                                    (ast::TyI64, ast::TyI8)  |
                                    (ast::TyI32, ast::TyI16) |
                                    (ast::TyI32, ast::TyI8)  |
                                    (ast::TyI16, ast::TyI8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", i1, i2)),
                                    _ => ()
                                }
                            },
                            (&ty::TyInt(i), &ty::TyUint(u)) => {
                                span_lint(cx, CAST_SIGN_LOSS, expr.span,
                                          &format!("casting from {} to {} loses the sign of the value", i, u));
                                match (i, u) {
                                    (ast::TyI64, ast::TyU32) |
                                    (ast::TyI64, ast::TyU16) |
                                    (ast::TyI64, ast::TyU8)  |
                                    (ast::TyI32, ast::TyU16) |
                                    (ast::TyI32, ast::TyU8)  |
                                    (ast::TyI16, ast::TyU8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", i, u)),
                                    _ => ()
                                }
                            },
                            (&ty::TyUint(u), &ty::TyInt(i)) => {
                                match (u, i) {
                                    (ast::TyU64, ast::TyI32) |
                                    (ast::TyU64, ast::TyI64) |
                                    (ast::TyU64, ast::TyI16) |
                                    (ast::TyU64, ast::TyI8)  |
                                    (ast::TyU32, ast::TyI32) |
                                    (ast::TyU32, ast::TyI16) |
                                    (ast::TyU32, ast::TyI8)  |
                                    (ast::TyU16, ast::TyI16) |
                                    (ast::TyU16, ast::TyI8)  |
                                    (ast::TyU8, ast::TyI8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", u, i)),
                                    _ => ()
                                }
                            },
                            (&ty::TyUint(u1), &ty::TyUint(u2)) => {
                                match (u1, u2) {
                                    (ast::TyU64, ast::TyU32) |
                                    (ast::TyU64, ast::TyU16) |
                                    (ast::TyU64, ast::TyU8)  |
                                    (ast::TyU32, ast::TyU16) |
                                    (ast::TyU32, ast::TyU8)  |
                                    (ast::TyU16, ast::TyU8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", u1, u2)),
                                    _ => ()
                                }
                            },
                            _ => ()
                        }
                    }
                    (false, false) => {
                        if let (&ty::TyFloat(ast::TyF64),
                                &ty::TyFloat(ast::TyF32)) = (&cast_from.sty, &cast_to.sty) {
                            span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, "the contents of a f64 may overflow a f32");
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>Fixed a little oversight.<commit_after>use rustc::lint::*;
use syntax::ast;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::ptr::P;
use rustc::middle::ty;
use syntax::codemap::ExpnInfo;

use utils::{in_macro, snippet, span_lint, span_help_and_lint, in_external_macro};

/// Handles all the linting of funky types
#[allow(missing_copy_implementations)]
pub struct TypePass;

declare_lint!(pub BOX_VEC, Warn,
              "usage of `Box<Vec<T>>`, vector elements are already on the heap");
declare_lint!(pub LINKEDLIST, Warn,
              "usage of LinkedList, usually a vector is faster, or a more specialized data \
               structure like a RingBuf");

/// Matches a type with a provided string, and returns its type parameters if successful
pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
    match ty.node {
        TyPath(_, Path {segments: ref seg, ..}) => {
            // So ast::Path isn't the full path, just the tokens that were provided.
            // I could muck around with the maps and find the full path
            // however the more efficient way is to simply reverse the iterators and zip them
            // which will compare them in reverse until one of them runs out of segments
            if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.name == b) {
                match seg[..].last() {
                    Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => {
                        Some(&a.types[..])
                    }
                    _ => None
                }
            } else {
                None
            }
        },
        _ => None
    }
}

#[allow(unused_imports)]
impl LintPass for TypePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(BOX_VEC, LINKEDLIST)
    }

    fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) {
        {
            // In case stuff gets moved around
            use std::boxed::Box;
            use std::vec::Vec;
        }
        match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first())
          .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"]))
          .map(|_| {
            span_help_and_lint(cx, BOX_VEC, ty.span,
                              "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?",
                              "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation");
          });
        {
            // In case stuff gets moved around
            use collections::linked_list::LinkedList as DL1;
            use std::collections::linked_list::LinkedList as DL2;
        }
        let dlists = [vec!["std","collections","linked_list","LinkedList"],
                      vec!["collections","linked_list","LinkedList"]];
        for path in &dlists {
            if match_ty_unwrap(ty, &path[..]).is_some() {
                span_help_and_lint(cx, LINKEDLIST, ty.span,
                                   "I see you're using a LinkedList! Perhaps you meant some other data structure?",
                                   "a RingBuf might work");
                return;
            }
        }
    }
}

#[allow(missing_copy_implementations)]
pub struct LetPass;

declare_lint!(pub LET_UNIT_VALUE, Warn,
              "creating a let binding to a value of unit type, which usually can't be used afterwards");

fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) {
    if in_macro(cx, info) { return; }
    if let DeclLocal(ref local) = decl.node {
        let bindtype = &cx.tcx.pat_ty(&*local.pat).sty;
        if *bindtype == ty::TyTuple(vec![]) {
            span_lint(cx, LET_UNIT_VALUE, decl.span, &format!(
                "this let-binding has unit value. Consider omitting `let {} =`",
                snippet(cx, local.pat.span, "..")));
        }
    }
}

impl LintPass for LetPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(LET_UNIT_VALUE)
    }

    fn check_decl(&mut self, cx: &Context, decl: &Decl) {
        cx.sess().codemap().with_expn_info(
            decl.span.expn_id,
            |info| check_let_unit(cx, decl, info));
    }
}

declare_lint!(pub UNIT_CMP, Warn,
              "comparing unit values (which is always `true` or `false`, respectively)");

#[allow(missing_copy_implementations)]
pub struct UnitCmp;

impl LintPass for UnitCmp {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNIT_CMP)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprBinary(ref cmp, ref left, _) = expr.node {
            let op = cmp.node;
            let sty = &cx.tcx.expr_ty(left).sty;
            if *sty == ty::TyTuple(vec![]) && is_comparison_binop(op) {
                let result = match op {
                    BiEq | BiLe | BiGe => "true",
                    _ => "false"
                };
                span_lint(cx, UNIT_CMP, expr.span, &format!(
                    "{}-comparison of unit values detected. This will always be {}",
                    binop_to_string(op), result));
            }
        }
    }
}

pub struct CastPass;

declare_lint!(pub CAST_PRECISION_LOSS, Allow,
              "casts that cause loss of precision, e.g `x as f32` where `x: u64`");
declare_lint!(pub CAST_SIGN_LOSS, Allow,
              "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`");
declare_lint!(pub CAST_POSSIBLE_OVERFLOW, Allow,
              "casts that may cause overflow, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`");

impl LintPass for CastPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(CAST_PRECISION_LOSS,
                    CAST_SIGN_LOSS,
                    CAST_POSSIBLE_OVERFLOW)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprCast(ref ex, _) = expr.node {
            let (cast_from, cast_to) = (cx.tcx.expr_ty(&*ex), cx.tcx.expr_ty(expr));
            if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) {
                match (cast_from.is_integral(), cast_to.is_integral()) {
                    (true, false)  => {
                        match (&cast_from.sty, &cast_to.sty) {
                            (&ty::TyInt(i), &ty::TyFloat(f)) => {
                                match (i, f) {
                                    (ast::TyI32, ast::TyF32) |
                                    (ast::TyI64, ast::TyF32) |
                                    (ast::TyI64, ast::TyF64) => {
                                        span_lint(cx, CAST_PRECISION_LOSS, expr.span,
                                                  &format!("converting from {} to {}, which causes a loss of precision",
                                                           i, f));
                                    },
                                    _ => ()
                                }
                            }
                            (&ty::TyUint(u), &ty::TyFloat(f)) => {
                                match (u, f) {
                                    (ast::TyU32, ast::TyF32) |
                                    (ast::TyU64, ast::TyF32) |
                                    (ast::TyU64, ast::TyF64) => {
                                        span_lint(cx, CAST_PRECISION_LOSS, expr.span,
                                                  &format!("converting from {} to {}, which causes a loss of precision",
                                                           u, f));
                                    },
                                    _ => ()
                                }
                            },
                            _ => ()
                        }
                    },
                    (false, true) => {
                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                  &format!("the contents of a {} may overflow a {}", cast_from, cast_to));
                        if !cast_to.is_signed() {
                            span_lint(cx, CAST_SIGN_LOSS, expr.span,
                                      &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to));
                        }
                    },
                    (true, true) => {
                        match (&cast_from.sty, &cast_to.sty) {
                            (&ty::TyInt(i1), &ty::TyInt(i2)) => {
                                match (i1, i2) {
                                    (ast::TyI64, ast::TyI32) |
                                    (ast::TyI64, ast::TyI16) |
                                    (ast::TyI64, ast::TyI8)  |
                                    (ast::TyI32, ast::TyI16) |
                                    (ast::TyI32, ast::TyI8)  |
                                    (ast::TyI16, ast::TyI8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", i1, i2)),
                                    _ => ()
                                }
                            },
                            (&ty::TyInt(i), &ty::TyUint(u)) => {
                                span_lint(cx, CAST_SIGN_LOSS, expr.span,
                                          &format!("casting from {} to {} loses the sign of the value", i, u));
                                match (i, u) {
                                    (ast::TyI64, ast::TyU32) |
                                    (ast::TyI64, ast::TyU16) |
                                    (ast::TyI64, ast::TyU8)  |
                                    (ast::TyI32, ast::TyU16) |
                                    (ast::TyI32, ast::TyU8)  |
                                    (ast::TyI16, ast::TyU8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", i, u)),
                                    _ => ()
                                }
                            },
                            (&ty::TyUint(u), &ty::TyInt(i)) => {
                                match (u, i) {
                                    (ast::TyU64, ast::TyI32) |
                                    (ast::TyU64, ast::TyI64) |
                                    (ast::TyU64, ast::TyI16) |
                                    (ast::TyU64, ast::TyI8)  |
                                    (ast::TyU32, ast::TyI32) |
                                    (ast::TyU32, ast::TyI16) |
                                    (ast::TyU32, ast::TyI8)  |
                                    (ast::TyU16, ast::TyI16) |
                                    (ast::TyU16, ast::TyI8)  |
                                    (ast::TyU8, ast::TyI8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", u, i)),
                                    _ => ()
                                }
                            },
                            (&ty::TyUint(u1), &ty::TyUint(u2)) => {
                                match (u1, u2) {
                                    (ast::TyU64, ast::TyU32) |
                                    (ast::TyU64, ast::TyU16) |
                                    (ast::TyU64, ast::TyU8)  |
                                    (ast::TyU32, ast::TyU16) |
                                    (ast::TyU32, ast::TyU8)  |
                                    (ast::TyU16, ast::TyU8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", u1, u2)),
                                    _ => ()
                                }
                            },
                            _ => ()
                        }
                    }
                    (false, false) => {
                        if let (&ty::TyFloat(ast::TyF64),
                                &ty::TyFloat(ast::TyF32)) = (&cast_from.sty, &cast_to.sty) {
                            span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, "the contents of a f64 may overflow a f32");
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>