<commit_before>//! Define table formatting utilities

use std::io::{Write, Error};

use encode_unicode::Utf8Char;

use super::utils::NEWLINE;

/// Alignment for cell's content
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum Alignment {
    LEFT,
    CENTER,
    RIGHT,
}

/// Position of a line separator in a table
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum LinePosition {
    Top,
    Title,
    Intern,
    Bottom,
}

/// Position of a column separator in a row
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum ColumnPosition {
    Left,
    Intern,
    Right,
}

/// Contains the character used for printing a line separator
#[derive(Clone, Debug, Copy)]
pub struct LineSeparator {
    /// Line separator
    line: char,
    /// Internal junction separator
    junc: char,
    /// Left junction separator
    ljunc: char,
    /// Right junction separator
    rjunc: char,
}

impl LineSeparator {
    /// Create a new line separator instance where `line` is the character used to separate 2 lines
    /// and `junc` is the one used for junctions between columns and lines
    pub fn new(line: char, junc: char, ljunc: char, rjunc: char) -> LineSeparator {
        LineSeparator {
            line: line,
            junc: junc,
            ljunc: ljunc,
            rjunc: rjunc,
        }
    }

    /// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
    #[deprecated(since = "0.6.7", note = "assumes padding is always (1, 1)")]
    pub fn print<T: Write + ?Sized>(&self,
                                    out: &mut T,
                                    col_width: &[usize],
                                    colsep: bool,
                                    lborder: bool,
                                    rborder: bool)
                                    -> Result<(), Error> {
        self.real_print(out, col_width, (1, 1), colsep, lborder, rborder)
    }

    fn real_print<T: Write + ?Sized>(&self,
                                     out: &mut T,
                                     col_width: &[usize],
                                     padding: (usize, usize),
                                     colsep: bool,
                                     lborder: bool,
                                     rborder: bool)
                                     -> Result<(), Error> {
        if lborder {
            try!(out.write_all(Utf8Char::from(self.ljunc).as_bytes()));
        }
        let mut iter = col_width.into_iter().peekable();
        while let Some(width) = iter.next() {
            for _ in 0..width + padding.0 + padding.1 {
                try!(out.write_all(Utf8Char::from(self.line).as_bytes()));
            }
            if colsep && iter.peek().is_some() {
                try!(out.write_all(Utf8Char::from(self.junc).as_bytes()));
            }
        }
        if rborder {
            try!(out.write_all(Utf8Char::from(self.rjunc).as_bytes()));
        }
        out.write_all(NEWLINE)
    }
}

impl Default for LineSeparator {
    fn default() -> Self {
        LineSeparator::new('-', '+', '+', '+')
    }
}

/// Contains the table formatting rules
#[derive(Clone, Debug, Copy)]
pub struct TableFormat {
    /// Optional column separator character
    csep: Option<char>,
    /// Optional left border character
    lborder: Option<char>,
    /// Optional right border character
    rborder: Option<char>,
    /// Optional internal line separator
    lsep: Option<LineSeparator>,
    /// Optional title line separator
    tsep: Option<LineSeparator>,
    /// Optional top line separator
    top_sep: Option<LineSeparator>,
    /// Optional bottom line separator
    bottom_sep: Option<LineSeparator>,
    /// Left padding
    pad_left: usize,
    /// Right padding
    pad_right: usize,
}

impl TableFormat {
    /// Create a new empty TableFormat.
    pub fn new() -> TableFormat {
        TableFormat {
            csep: None,
            lborder: None,
            rborder: None,
            lsep: None,
            tsep: None,
            top_sep: None,
            bottom_sep: None,
            pad_left: 0,
            pad_right: 0,
        }
    }

    /// Return a tuple with left and right padding
    pub fn get_padding(&self) -> (usize, usize) {
        (self.pad_left, self.pad_right)
    }

    /// Set left and right padding
    pub fn padding(&mut self, left: usize, right: usize) {
        self.pad_left = left;
        self.pad_right = right;
    }

    /// Set the character used for internal column separation
    pub fn column_separator(&mut self, separator: char) {
        self.csep = Some(separator);
    }

    /// Set the character used for table borders
    pub fn borders(&mut self, border: char) {
        self.lborder = Some(border);
        self.rborder = Some(border);
    }

    /// Set a line separator
    pub fn separator(&mut self, what: LinePosition, separator: LineSeparator) {
        *match what {
             LinePosition::Top => &mut self.top_sep,
             LinePosition::Bottom => &mut self.bottom_sep,
             LinePosition::Title => &mut self.tsep,
             LinePosition::Intern => &mut self.lsep,
         } = Some(separator);
    }

    /// Set format for multiple kind of line separator
    pub fn separators(&mut self, what: &[LinePosition], separator: LineSeparator) {
        for pos in what {
            self.separator(*pos, separator);
        }
    }

    fn get_sep_for_line(&self, pos: LinePosition) -> &Option<LineSeparator> {
        match pos {
            LinePosition::Intern => return &self.lsep,
            LinePosition::Top => return &self.top_sep,
            LinePosition::Bottom => return &self.bottom_sep,
            LinePosition::Title => {
                match &self.tsep {
                    s @ &Some(_) => s,
                    &None => &self.lsep,
                }
            }
        }
    }

    /// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
    pub fn print_line_separator<T: Write + ?Sized>(&self,
                                                   out: &mut T,
                                                   col_width: &[usize],
                                                   pos: LinePosition)
                                                   -> Result<(), Error> {
        match *self.get_sep_for_line(pos) {
            Some(ref l) => {
                l.real_print(out,
                             col_width,
                             self.get_padding(),
                             self.csep.is_some(),
                             self.lborder.is_some(),
                             self.rborder.is_some())
            }
            None => Ok(()),
        }
    }

    pub fn get_column_separator(&self, pos: ColumnPosition) -> Option<char> {
        match pos {
            ColumnPosition::Left => self.lborder,
            ColumnPosition::Intern => self.csep,
            ColumnPosition::Right => self.rborder,
        }
    }

    /// Print a column separator or a table border
    pub fn print_column_separator<T: Write + ?Sized>(&self,
                                                     out: &mut T,
                                                     pos: ColumnPosition)
                                                     -> Result<(), Error> {
        match self.get_column_separator(pos) {
            Some(s) => out.write_all(Utf8Char::from(s).as_bytes()),
            None => Ok(()),
        }
    }
}

impl Default for TableFormat {
    fn default() -> Self {
        TableFormat::new()
    }
}

/// A builder to create a `TableFormat`
pub struct FormatBuilder {
    format: Box<TableFormat>,
}

impl FormatBuilder {
    pub fn new() -> FormatBuilder {
        FormatBuilder { format: Box::new(TableFormat::new()) }
    }

    /// Set left and right padding
    pub fn padding(mut self, left: usize, right: usize) -> Self {
        self.format.padding(left, right);
        self
    }

    /// Set the character used for internal column separation
    pub fn column_separator(mut self, separator: char) -> Self {
        self.format.column_separator(separator);
        self
    }

    /// Set the character used for table borders
    pub fn borders(mut self, border: char) -> Self {
        self.format.borders(border);
        self
    }

    /// Set a line separator format
    pub fn separator(mut self, what: LinePosition, separator: LineSeparator) -> Self {
        self.format.separator(what, separator);
        self
    }

    /// Set separator format for multiple kind of line separators
    pub fn separators(mut self, what: &[LinePosition], separator: LineSeparator) -> Self {
        self.format.separators(what, separator);
        self
    }

    /// Consume this builder and return the generated `TableFormat`
    pub fn build(self) -> TableFormat {
        *self.format
    }
}

/// Predifined formats. Those constants are lazily evaluated when
/// the corresponding struct is dereferenced
pub mod consts {
    use super::{TableFormat, LineSeparator, FormatBuilder, LinePosition};

    lazy_static! {
        /// A line separator made of `-` and `+`
        static ref MINUS_PLUS_SEP: LineSeparator = LineSeparator::new('-', '+', '+', '+');
        /// A line separator made of `=` and `+`
        static ref EQU_PLUS_SEP: LineSeparator = LineSeparator::new('=', '+', '+', '+');

        /// Default table format
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +====+====+
        /// | a  | b  |
        /// +----+----+
        /// | d  | c  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_DEFAULT: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// Similar to `FORMAT_DEFAULT` but without special separator after title line
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +----+----+
        /// | a  | b  |
        /// +----+----+
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_TITLE: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// With no line separator, but with title separator
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +----+----+
        /// | a  | b  |
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_LINESEP_WITH_TITLE: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// With no line or title separator
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// | a  | b  |
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_LINESEP: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// No column separator
        ///
        /// # Example
        /// ```text
        /// --------
        ///  T1  T2
        /// ========
        ///  a   b
        /// --------
        ///  d   c
        /// --------
        /// ```
        pub static ref FORMAT_NO_COLSEP: TableFormat = FormatBuilder::new()
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// Format for printing a table without any separators (only alignment)
        ///
        /// # Example
        /// ```text
        ///  T1  T2
        ///  a   b
        ///  d   c
        /// ```
        pub static ref FORMAT_CLEAN: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .build();

        /// Format for a table with only external borders and title separator
        ///
        /// # Example
        /// ```text
        /// +--------+
        /// | T1  T2 |
        /// +========+
        /// | a   b  |
        /// | c   d  |
        /// +--------+
        /// ```
        pub static ref FORMAT_BORDERS_ONLY: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .borders('|')
                                                                    .build();

        /// A table with no external border
        ///
        /// # Example
        /// ```text
        ///  T1 | T2
        /// ====+====
        ///  a  | b
        /// ----+----
        ///  c  | d
        /// ```
        pub static ref FORMAT_NO_BORDER: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .column_separator('|')
                                                                    .build();

        /// A table with no external border and no line separation
        ///
        /// # Example
        /// ```text
        ///  T1 | T2
        /// ----+----
        ///  a  | b
        ///  c  | d
        /// ```
        pub static ref FORMAT_NO_BORDER_LINE_SEPARATOR: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .column_separator('|')
                                                                    .build();
    }
}
<commit_msg>Make deprecation note and function name more clear<commit_after>//! Define table formatting utilities

use std::io::{Write, Error};

use encode_unicode::Utf8Char;

use super::utils::NEWLINE;

/// Alignment for cell's content
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum Alignment {
    LEFT,
    CENTER,
    RIGHT,
}

/// Position of a line separator in a table
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum LinePosition {
    Top,
    Title,
    Intern,
    Bottom,
}

/// Position of a column separator in a row
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum ColumnPosition {
    Left,
    Intern,
    Right,
}

/// Contains the character used for printing a line separator
#[derive(Clone, Debug, Copy)]
pub struct LineSeparator {
    /// Line separator
    line: char,
    /// Internal junction separator
    junc: char,
    /// Left junction separator
    ljunc: char,
    /// Right junction separator
    rjunc: char,
}

impl LineSeparator {
    /// Create a new line separator instance where `line` is the character used to separate 2 lines
    /// and `junc` is the one used for junctions between columns and lines
    pub fn new(line: char, junc: char, ljunc: char, rjunc: char) -> LineSeparator {
        LineSeparator {
            line: line,
            junc: junc,
            ljunc: ljunc,
            rjunc: rjunc,
        }
    }

    /// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
    #[deprecated(since = "0.6.7", note = "function will be removed. See [issue #57](https://github.com/phsym/prettytable-rs/pull/57).")]
    pub fn print<T: Write + ?Sized>(&self,
                                    out: &mut T,
                                    col_width: &[usize],
                                    colsep: bool,
                                    lborder: bool,
                                    rborder: bool)
                                    -> Result<(), Error> {
        self._print(out, col_width, (1, 1), colsep, lborder, rborder)
    }

    fn _print<T: Write + ?Sized>(&self,
                                 out: &mut T,
                                 col_width: &[usize],
                                 padding: (usize, usize),
                                 colsep: bool,
                                 lborder: bool,
                                 rborder: bool)
                                 -> Result<(), Error> {
        if lborder {
            try!(out.write_all(Utf8Char::from(self.ljunc).as_bytes()));
        }
        let mut iter = col_width.into_iter().peekable();
        while let Some(width) = iter.next() {
            for _ in 0..width + padding.0 + padding.1 {
                try!(out.write_all(Utf8Char::from(self.line).as_bytes()));
            }
            if colsep && iter.peek().is_some() {
                try!(out.write_all(Utf8Char::from(self.junc).as_bytes()));
            }
        }
        if rborder {
            try!(out.write_all(Utf8Char::from(self.rjunc).as_bytes()));
        }
        out.write_all(NEWLINE)
    }
}

impl Default for LineSeparator {
    fn default() -> Self {
        LineSeparator::new('-', '+', '+', '+')
    }
}

/// Contains the table formatting rules
#[derive(Clone, Debug, Copy)]
pub struct TableFormat {
    /// Optional column separator character
    csep: Option<char>,
    /// Optional left border character
    lborder: Option<char>,
    /// Optional right border character
    rborder: Option<char>,
    /// Optional internal line separator
    lsep: Option<LineSeparator>,
    /// Optional title line separator
    tsep: Option<LineSeparator>,
    /// Optional top line separator
    top_sep: Option<LineSeparator>,
    /// Optional bottom line separator
    bottom_sep: Option<LineSeparator>,
    /// Left padding
    pad_left: usize,
    /// Right padding
    pad_right: usize,
}

impl TableFormat {
    /// Create a new empty TableFormat.
    pub fn new() -> TableFormat {
        TableFormat {
            csep: None,
            lborder: None,
            rborder: None,
            lsep: None,
            tsep: None,
            top_sep: None,
            bottom_sep: None,
            pad_left: 0,
            pad_right: 0,
        }
    }

    /// Return a tuple with left and right padding
    pub fn get_padding(&self) -> (usize, usize) {
        (self.pad_left, self.pad_right)
    }

    /// Set left and right padding
    pub fn padding(&mut self, left: usize, right: usize) {
        self.pad_left = left;
        self.pad_right = right;
    }

    /// Set the character used for internal column separation
    pub fn column_separator(&mut self, separator: char) {
        self.csep = Some(separator);
    }

    /// Set the character used for table borders
    pub fn borders(&mut self, border: char) {
        self.lborder = Some(border);
        self.rborder = Some(border);
    }

    /// Set a line separator
    pub fn separator(&mut self, what: LinePosition, separator: LineSeparator) {
        *match what {
             LinePosition::Top => &mut self.top_sep,
             LinePosition::Bottom => &mut self.bottom_sep,
             LinePosition::Title => &mut self.tsep,
             LinePosition::Intern => &mut self.lsep,
         } = Some(separator);
    }

    /// Set format for multiple kind of line separator
    pub fn separators(&mut self, what: &[LinePosition], separator: LineSeparator) {
        for pos in what {
            self.separator(*pos, separator);
        }
    }

    fn get_sep_for_line(&self, pos: LinePosition) -> &Option<LineSeparator> {
        match pos {
            LinePosition::Intern => return &self.lsep,
            LinePosition::Top => return &self.top_sep,
            LinePosition::Bottom => return &self.bottom_sep,
            LinePosition::Title => {
                match &self.tsep {
                    s @ &Some(_) => s,
                    &None => &self.lsep,
                }
            }
        }
    }

    /// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
    pub fn print_line_separator<T: Write + ?Sized>(&self,
                                                   out: &mut T,
                                                   col_width: &[usize],
                                                   pos: LinePosition)
                                                   -> Result<(), Error> {
        match *self.get_sep_for_line(pos) {
            Some(ref l) => {
                l._print(out,
                         col_width,
                         self.get_padding(),
                         self.csep.is_some(),
                         self.lborder.is_some(),
                         self.rborder.is_some())
            }
            None => Ok(()),
        }
    }

    pub fn get_column_separator(&self, pos: ColumnPosition) -> Option<char> {
        match pos {
            ColumnPosition::Left => self.lborder,
            ColumnPosition::Intern => self.csep,
            ColumnPosition::Right => self.rborder,
        }
    }

    /// Print a column separator or a table border
    pub fn print_column_separator<T: Write + ?Sized>(&self,
                                                     out: &mut T,
                                                     pos: ColumnPosition)
                                                     -> Result<(), Error> {
        match self.get_column_separator(pos) {
            Some(s) => out.write_all(Utf8Char::from(s).as_bytes()),
            None => Ok(()),
        }
    }
}

impl Default for TableFormat {
    fn default() -> Self {
        TableFormat::new()
    }
}

/// A builder to create a `TableFormat`
pub struct FormatBuilder {
    format: Box<TableFormat>,
}

impl FormatBuilder {
    pub fn new() -> FormatBuilder {
        FormatBuilder { format: Box::new(TableFormat::new()) }
    }

    /// Set left and right padding
    pub fn padding(mut self, left: usize, right: usize) -> Self {
        self.format.padding(left, right);
        self
    }

    /// Set the character used for internal column separation
    pub fn column_separator(mut self, separator: char) -> Self {
        self.format.column_separator(separator);
        self
    }

    /// Set the character used for table borders
    pub fn borders(mut self, border: char) -> Self {
        self.format.borders(border);
        self
    }

    /// Set a line separator format
    pub fn separator(mut self, what: LinePosition, separator: LineSeparator) -> Self {
        self.format.separator(what, separator);
        self
    }

    /// Set separator format for multiple kind of line separators
    pub fn separators(mut self, what: &[LinePosition], separator: LineSeparator) -> Self {
        self.format.separators(what, separator);
        self
    }

    /// Consume this builder and return the generated `TableFormat`
    pub fn build(self) -> TableFormat {
        *self.format
    }
}

/// Predifined formats. Those constants are lazily evaluated when
/// the corresponding struct is dereferenced
pub mod consts {
    use super::{TableFormat, LineSeparator, FormatBuilder, LinePosition};

    lazy_static! {
        /// A line separator made of `-` and `+`
        static ref MINUS_PLUS_SEP: LineSeparator = LineSeparator::new('-', '+', '+', '+');
        /// A line separator made of `=` and `+`
        static ref EQU_PLUS_SEP: LineSeparator = LineSeparator::new('=', '+', '+', '+');

        /// Default table format
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +====+====+
        /// | a  | b  |
        /// +----+----+
        /// | d  | c  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_DEFAULT: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// Similar to `FORMAT_DEFAULT` but without special separator after title line
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +----+----+
        /// | a  | b  |
        /// +----+----+
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_TITLE: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// With no line separator, but with title separator
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +----+----+
        /// | a  | b  |
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_LINESEP_WITH_TITLE: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// With no line or title separator
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// | a  | b  |
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_LINESEP: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// No column separator
        ///
        /// # Example
        /// ```text
        /// --------
        ///  T1  T2
        /// ========
        ///  a   b
        /// --------
        ///  d   c
        /// --------
        /// ```
        pub static ref FORMAT_NO_COLSEP: TableFormat = FormatBuilder::new()
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// Format for printing a table without any separators (only alignment)
        ///
        /// # Example
        /// ```text
        ///  T1  T2
        ///  a   b
        ///  d   c
        /// ```
        pub static ref FORMAT_CLEAN: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .build();

        /// Format for a table with only external borders and title separator
        ///
        /// # Example
        /// ```text
        /// +--------+
        /// | T1  T2 |
        /// +========+
        /// | a   b  |
        /// | c   d  |
        /// +--------+
        /// ```
        pub static ref FORMAT_BORDERS_ONLY: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .borders('|')
                                                                    .build();

        /// A table with no external border
        ///
        /// # Example
        /// ```text
        ///  T1 | T2
        /// ====+====
        ///  a  | b
        /// ----+----
        ///  c  | d
        /// ```
        pub static ref FORMAT_NO_BORDER: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .column_separator('|')
                                                                    .build();

        /// A table with no external border and no line separation
        ///
        /// # Example
        /// ```text
        ///  T1 | T2
        /// ----+----
        ///  a  | b
        ///  c  | d
        /// ```
        pub static ref FORMAT_NO_BORDER_LINE_SEPARATOR: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .column_separator('|')
                                                                    .build();
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A standard, garbage-collected linked list.

#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub enum List<T> {
    Cons(T, @List<T>),
    Nil,
}

/// Create a list from a vector
pub fn from_vec<T:Clone + 'static>(v: &[T]) -> @List<T> {
    v.rev_iter().fold(@Nil::<T>, |t, h| @Cons((*h).clone(), t))
}

/**
 * Left fold
 *
 * Applies `f` to `u` and the first element in the list, then applies `f` to
 * the result of the previous call and the second element, and so on,
 * returning the accumulated result.
 *
 * # Arguments
 *
 * * ls - The list to fold
 * * z - The initial value
 * * f - The function to apply
 */
pub fn foldl<T:Clone,U>(z: T, ls: @List<U>, f: |&T, &U| -> T) -> T {
    let mut accum: T = z;
    iter(ls, |elt| accum = f(&accum, elt));
    accum
}

/**
 * Search for an element that matches a given predicate
 *
 * Apply function `f` to each element of `v`, starting from the first.
 * When function `f` returns true then an option containing the element
 * is returned. If `f` matches no elements then none is returned.
 */
pub fn find<T:Clone>(ls: @List<T>, f: |&T| -> bool) -> Option<T> {
    let mut ls = ls;
    loop {
        ls = match *ls {
          Cons(ref hd, tl) => {
            if f(hd) { return Some((*hd).clone()); }
            tl
          }
          Nil => return None
        }
    };
}

/// Returns true if a list contains an element with the given value
pub fn has<T:Eq>(ls: @List<T>, elt: T) -> bool {
    let mut found = false;
    each(ls, |e| {
        if *e == elt { found = true; false } else { true }
    });
    return found;
}

/// Returns true if the list is empty
pub fn is_empty<T>(ls: @List<T>) -> bool {
    match *ls {
        Nil => true,
        _ => false
    }
}

/// Returns the length of a list
pub fn len<T>(ls: @List<T>) -> uint {
    let mut count = 0u;
    iter(ls, |_e| count += 1u);
    count
}

/// Returns all but the first element of a list
pub fn tail<T>(ls: @List<T>) -> @List<T> {
    match *ls {
        Cons(_, tl) => return tl,
        Nil => fail!("list empty")
    }
}

/// Returns the first element of a list
pub fn head<T:Clone>(ls: @List<T>) -> T {
    match *ls {
      Cons(ref hd, _) => (*hd).clone(),
      // makes me sad
      _ => fail!("head invoked on empty list")
    }
}

/// Appends one list to another
pub fn append<T:Clone + 'static>(l: @List<T>, m: @List<T>) -> @List<T> {
    match *l {
      Nil => return m,
      Cons(ref x, xs) => {
        let rest = append(xs, m);
        return @Cons((*x).clone(), rest);
      }
    }
}

/*
/// Push one element into the front of a list, returning a new list
/// THIS VERSION DOESN'T ACTUALLY WORK
fn push<T:Clone>(ll: &mut @list<T>, vv: T) {
    ll = &mut @cons(vv, *ll)
}
*/

/// Iterate over a list
pub fn iter<T>(l: @List<T>, f: |&T|) {
    let mut cur = l;
    loop {
        cur = match *cur {
          Cons(ref hd, tl) => {
            f(hd);
            tl
          }
          Nil => break
        }
    }
}

/// Iterate over a list
pub fn each<T>(l: @List<T>, f: |&T| -> bool) -> bool {
    let mut cur = l;
    loop {
        cur = match *cur {
          Cons(ref hd, tl) => {
            if !f(hd) { return false; }
            tl
          }
          Nil => { return true; }
        }
    }
}

#[cfg(test)]
mod tests {
    use list::{List, Nil, from_vec, head, is_empty, tail};
    use list;

    use std::option;

    #[test]
    fn test_is_empty() {
        let empty : @list::List<int> = from_vec([]);
        let full1 = from_vec([1]);
        let full2 = from_vec(['r', 'u']);

        assert!(is_empty(empty));
        assert!(!is_empty(full1));
        assert!(!is_empty(full2));
    }

    #[test]
    fn test_from_vec() {
        let l = from_vec([0, 1, 2]);

        assert_eq!(head(l), 0);

        let tail_l = tail(l);
        assert_eq!(head(tail_l), 1);

        let tail_tail_l = tail(tail_l);
        assert_eq!(head(tail_tail_l), 2);
    }

    #[test]
    fn test_from_vec_empty() {
        let empty : @list::List<int> = from_vec([]);
        assert_eq!(empty, @list::Nil::<int>);
    }

    #[test]
    fn test_foldl() {
        fn add(a: &uint, b: &int) -> uint { return *a + (*b as uint); }
        let l = from_vec([0, 1, 2, 3, 4]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::foldl(0u, l, add), 10u);
        assert_eq!(list::foldl(0u, empty, add), 0u);
    }

    #[test]
    fn test_foldl2() {
        fn sub(a: &int, b: &int) -> int {
            *a - *b
        }
        let l = from_vec([1, 2, 3, 4]);
        assert_eq!(list::foldl(0, l, sub), -10);
    }

    #[test]
    fn test_find_success() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let l = from_vec([0, 1, 2]);
        assert_eq!(list::find(l, match_), option::Some(2));
    }

    #[test]
    fn test_find_fail() {
        fn match_(_i: &int) -> bool { return false; }
        let l = from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::find(l, match_), option::None::<int>);
        assert_eq!(list::find(empty, match_), option::None::<int>);
    }

    #[test]
    fn test_has() {
        let l = from_vec([5, 8, 6]);
        let empty = @list::Nil::<int>;
        assert!((list::has(l, 5)));
        assert!((!list::has(l, 7)));
        assert!((list::has(l, 8)));
        assert!((!list::has(empty, 5)));
    }

    #[test]
    fn test_len() {
        let l = from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::len(l), 3u);
        assert_eq!(list::len(empty), 0u);
    }

    #[test]
    fn test_append() {
        assert!(from_vec([1,2,3,4])
            == list::append(list::from_vec([1,2]), list::from_vec([3,4])));
    }
}
<commit_msg>auto merge of #12131 : brunoabinader/rust/list-find-doc-typo, r=alexcrichton<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A standard, garbage-collected linked list.

#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub enum List<T> {
    Cons(T, @List<T>),
    Nil,
}

/// Create a list from a vector
pub fn from_vec<T:Clone + 'static>(v: &[T]) -> @List<T> {
    v.rev_iter().fold(@Nil::<T>, |t, h| @Cons((*h).clone(), t))
}

/**
 * Left fold
 *
 * Applies `f` to `u` and the first element in the list, then applies `f` to
 * the result of the previous call and the second element, and so on,
 * returning the accumulated result.
 *
 * # Arguments
 *
 * * ls - The list to fold
 * * z - The initial value
 * * f - The function to apply
 */
pub fn foldl<T:Clone,U>(z: T, ls: @List<U>, f: |&T, &U| -> T) -> T {
    let mut accum: T = z;
    iter(ls, |elt| accum = f(&accum, elt));
    accum
}

/**
 * Search for an element that matches a given predicate
 *
 * Apply function `f` to each element of `ls`, starting from the first.
 * When function `f` returns true then an option containing the element
 * is returned. If `f` matches no elements then none is returned.
 */
pub fn find<T:Clone>(ls: @List<T>, f: |&T| -> bool) -> Option<T> {
    let mut ls = ls;
    loop {
        ls = match *ls {
          Cons(ref hd, tl) => {
            if f(hd) { return Some((*hd).clone()); }
            tl
          }
          Nil => return None
        }
    };
}

/// Returns true if a list contains an element with the given value
pub fn has<T:Eq>(ls: @List<T>, elt: T) -> bool {
    let mut found = false;
    each(ls, |e| {
        if *e == elt { found = true; false } else { true }
    });
    return found;
}

/// Returns true if the list is empty
pub fn is_empty<T>(ls: @List<T>) -> bool {
    match *ls {
        Nil => true,
        _ => false
    }
}

/// Returns the length of a list
pub fn len<T>(ls: @List<T>) -> uint {
    let mut count = 0u;
    iter(ls, |_e| count += 1u);
    count
}

/// Returns all but the first element of a list
pub fn tail<T>(ls: @List<T>) -> @List<T> {
    match *ls {
        Cons(_, tl) => return tl,
        Nil => fail!("list empty")
    }
}

/// Returns the first element of a list
pub fn head<T:Clone>(ls: @List<T>) -> T {
    match *ls {
      Cons(ref hd, _) => (*hd).clone(),
      // makes me sad
      _ => fail!("head invoked on empty list")
    }
}

/// Appends one list to another
pub fn append<T:Clone + 'static>(l: @List<T>, m: @List<T>) -> @List<T> {
    match *l {
      Nil => return m,
      Cons(ref x, xs) => {
        let rest = append(xs, m);
        return @Cons((*x).clone(), rest);
      }
    }
}

/*
/// Push one element into the front of a list, returning a new list
/// THIS VERSION DOESN'T ACTUALLY WORK
fn push<T:Clone>(ll: &mut @list<T>, vv: T) {
    ll = &mut @cons(vv, *ll)
}
*/

/// Iterate over a list
pub fn iter<T>(l: @List<T>, f: |&T|) {
    let mut cur = l;
    loop {
        cur = match *cur {
          Cons(ref hd, tl) => {
            f(hd);
            tl
          }
          Nil => break
        }
    }
}

/// Iterate over a list
pub fn each<T>(l: @List<T>, f: |&T| -> bool) -> bool {
    let mut cur = l;
    loop {
        cur = match *cur {
          Cons(ref hd, tl) => {
            if !f(hd) { return false; }
            tl
          }
          Nil => { return true; }
        }
    }
}

#[cfg(test)]
mod tests {
    use list::{List, Nil, from_vec, head, is_empty, tail};
    use list;

    use std::option;

    #[test]
    fn test_is_empty() {
        let empty : @list::List<int> = from_vec([]);
        let full1 = from_vec([1]);
        let full2 = from_vec(['r', 'u']);

        assert!(is_empty(empty));
        assert!(!is_empty(full1));
        assert!(!is_empty(full2));
    }

    #[test]
    fn test_from_vec() {
        let l = from_vec([0, 1, 2]);

        assert_eq!(head(l), 0);

        let tail_l = tail(l);
        assert_eq!(head(tail_l), 1);

        let tail_tail_l = tail(tail_l);
        assert_eq!(head(tail_tail_l), 2);
    }

    #[test]
    fn test_from_vec_empty() {
        let empty : @list::List<int> = from_vec([]);
        assert_eq!(empty, @list::Nil::<int>);
    }

    #[test]
    fn test_foldl() {
        fn add(a: &uint, b: &int) -> uint { return *a + (*b as uint); }
        let l = from_vec([0, 1, 2, 3, 4]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::foldl(0u, l, add), 10u);
        assert_eq!(list::foldl(0u, empty, add), 0u);
    }

    #[test]
    fn test_foldl2() {
        fn sub(a: &int, b: &int) -> int {
            *a - *b
        }
        let l = from_vec([1, 2, 3, 4]);
        assert_eq!(list::foldl(0, l, sub), -10);
    }

    #[test]
    fn test_find_success() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let l = from_vec([0, 1, 2]);
        assert_eq!(list::find(l, match_), option::Some(2));
    }

    #[test]
    fn test_find_fail() {
        fn match_(_i: &int) -> bool { return false; }
        let l = from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::find(l, match_), option::None::<int>);
        assert_eq!(list::find(empty, match_), option::None::<int>);
    }

    #[test]
    fn test_has() {
        let l = from_vec([5, 8, 6]);
        let empty = @list::Nil::<int>;
        assert!((list::has(l, 5)));
        assert!((!list::has(l, 7)));
        assert!((list::has(l, 8)));
        assert!((!list::has(empty, 5)));
    }

    #[test]
    fn test_len() {
        let l = from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::len(l), 3u);
        assert_eq!(list::len(empty), 0u);
    }

    #[test]
    fn test_append() {
        assert!(from_vec([1,2,3,4])
            == list::append(list::from_vec([1,2]), list::from_vec([3,4])));
    }
}
<|endoftext|>


<commit_before>//! Metrics
//!
//! Varz are updated by pretty much all components, using only two
//! operations: set() and inc().

use coarsetime::Instant;
use prometheus::{Counter, Gauge, Histogram};

pub struct StartInstant(pub Instant);

pub struct Varz {
    pub start_instant: StartInstant,
    pub uptime: Gauge,
    pub cache_frequent_len: Gauge,
    pub cache_recent_len: Gauge,
    pub cache_test_len: Gauge,
    pub cache_inserted: Gauge,
    pub cache_evicted: Gauge,
    pub client_queries: Gauge,
    pub client_queries_udp: Counter,
    pub client_queries_tcp: Counter,
    pub client_queries_cached: Counter,
    pub client_queries_expired: Counter,
    pub client_queries_offline: Counter,
    pub client_queries_errors: Counter,
    pub inflight_queries: Gauge,
    pub upstream_errors: Counter,
    pub upstream_sent: Counter,
    pub upstream_received: Counter,
    pub upstream_timeout: Counter,
    pub upstream_avg_rtt: Gauge,
    pub upstream_response_sizes: Histogram,
}

impl Varz {
    pub fn new() -> Varz {
        Varz {
            start_instant: StartInstant::default(),
            uptime: register_gauge!(opts!("edgedns_uptime",
                                          "Uptime",
                                          labels!{"handler" => "all",}))
                    .unwrap(),
            cache_frequent_len: register_gauge!(opts!("edgedns_cache_frequent_len",
                                                      "Number of entries in the cached set of \
                                                       frequent items",
                                                      labels!{"handler" => "all",}))
                    .unwrap(),
            cache_recent_len: register_gauge!(opts!("edgedns_cache_recent_len",
                                                    "Number of entries in the cached set of \
                                                     recent items",
                                                    labels!{"handler" => "all",}))
                    .unwrap(),
            cache_test_len: register_gauge!(opts!("edgedns_cache_test_len",
                                                  "Number of entries in the cached set of \
                                                   staged items",
                                                  labels!{"handler" => "all",}))
                    .unwrap(),
            cache_inserted: register_gauge!(opts!("edgedns_cache_inserted",
                                                  "Number of entries added to the cache",
                                                  labels!{"handler" => "all",}))
                    .unwrap(),
            cache_evicted: register_gauge!(opts!("edgedns_cache_evicted",
                                                 "Number of entries evicted from the cache",
                                                 labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries: register_gauge!(opts!("edgedns_client_queries",
                                                  "Number of client queries received",
                                                  labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_udp: register_counter!(opts!("edgedns_client_queries_udp",
                                                        "Number of client queries received \
                                                         using UDP",
                                                        labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_tcp: register_counter!(opts!("edgedns_client_queries_tcp",
                                                        "Number of client queries received \
                                                         using TCP",
                                                        labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_cached: register_counter!(opts!("edgedns_client_queries_cached",
                                                           "Number of client queries sent from \
                                                            the cache",
                                                           labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_expired: register_counter!(opts!("edgedns_client_queries_expired",
                                                            "Number of expired client queries",
                                                            labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_offline: register_counter!(opts!("edgedns_client_queries_offline",
                                                            "Number of client queries answered \
                                                             while upstream resolvers are \
                                                             unresponsive",
                                                            labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_errors: register_counter!(opts!("edgedns_client_queries_errors",
                                                           "Number of bogus client queries",
                                                           labels!{"handler" => "all",}))
                    .unwrap(),
            inflight_queries:
                register_gauge!(opts!("edgedns_inflight_queries",
                                      "Number of queries currently waiting for a response",
                                      labels!{"handler" => "all",}))
                        .unwrap(),
            upstream_errors: register_counter!(opts!("edgedns_upstream_errors",
                                                     "Number of bogus upstream servers responses",
                                                     labels!{"handler" => "all",}))
                    .unwrap(),
            upstream_sent: register_counter!(opts!("edgedns_upstream_sent",
                                                   "Number of upstream servers queries sent",
                                                   labels!{"handler" => "all",}))
                    .unwrap(),
            upstream_received:
                register_counter!(opts!("edgedns_upstream_received",
                                        "Number of upstream servers responses received",
                                        labels!{"handler" => "all",}))
                        .unwrap(),
            upstream_timeout: register_counter!(opts!("edgedns_upstream_timeout",
                                                      "Number of upstream servers responses \
                                                       having timed out",
                                                      labels!{"handler" => "all",}))
                    .unwrap(),
            upstream_avg_rtt: register_gauge!(opts!("edgedns_upstream_avg_rtt",
                                                    "Average RTT to upstream servers",
                                                    labels!{"handler" => "all",}))
                    .unwrap(),
            upstream_response_sizes: register_histogram!("Size of responses received from upstream servers",
                                                         "Response size in bytes.")
                    .unwrap(),
        }
    }
}

impl Default for Varz {
    fn default() -> Self {
        Self::new()
    }
}

impl Default for StartInstant {
    fn default() -> StartInstant {
        StartInstant(Instant::now())
    }
}
<commit_msg>Properly name the response sizes histogram<commit_after>//! Metrics
//!
//! Varz are updated by pretty much all components, using only two
//! operations: set() and inc().

use coarsetime::Instant;
use prometheus::{Counter, Gauge, Histogram};

pub struct StartInstant(pub Instant);

pub struct Varz {
    pub start_instant: StartInstant,
    pub uptime: Gauge,
    pub cache_frequent_len: Gauge,
    pub cache_recent_len: Gauge,
    pub cache_test_len: Gauge,
    pub cache_inserted: Gauge,
    pub cache_evicted: Gauge,
    pub client_queries: Gauge,
    pub client_queries_udp: Counter,
    pub client_queries_tcp: Counter,
    pub client_queries_cached: Counter,
    pub client_queries_expired: Counter,
    pub client_queries_offline: Counter,
    pub client_queries_errors: Counter,
    pub inflight_queries: Gauge,
    pub upstream_errors: Counter,
    pub upstream_sent: Counter,
    pub upstream_received: Counter,
    pub upstream_timeout: Counter,
    pub upstream_avg_rtt: Gauge,
    pub upstream_response_sizes: Histogram,
}

impl Varz {
    pub fn new() -> Varz {
        Varz {
            start_instant: StartInstant::default(),
            uptime: register_gauge!(opts!("edgedns_uptime",
                                          "Uptime",
                                          labels!{"handler" => "all",}))
                    .unwrap(),
            cache_frequent_len: register_gauge!(opts!("edgedns_cache_frequent_len",
                                                      "Number of entries in the cached set of \
                                                       frequent items",
                                                      labels!{"handler" => "all",}))
                    .unwrap(),
            cache_recent_len: register_gauge!(opts!("edgedns_cache_recent_len",
                                                    "Number of entries in the cached set of \
                                                     recent items",
                                                    labels!{"handler" => "all",}))
                    .unwrap(),
            cache_test_len: register_gauge!(opts!("edgedns_cache_test_len",
                                                  "Number of entries in the cached set of \
                                                   staged items",
                                                  labels!{"handler" => "all",}))
                    .unwrap(),
            cache_inserted: register_gauge!(opts!("edgedns_cache_inserted",
                                                  "Number of entries added to the cache",
                                                  labels!{"handler" => "all",}))
                    .unwrap(),
            cache_evicted: register_gauge!(opts!("edgedns_cache_evicted",
                                                 "Number of entries evicted from the cache",
                                                 labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries: register_gauge!(opts!("edgedns_client_queries",
                                                  "Number of client queries received",
                                                  labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_udp: register_counter!(opts!("edgedns_client_queries_udp",
                                                        "Number of client queries received \
                                                         using UDP",
                                                        labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_tcp: register_counter!(opts!("edgedns_client_queries_tcp",
                                                        "Number of client queries received \
                                                         using TCP",
                                                        labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_cached: register_counter!(opts!("edgedns_client_queries_cached",
                                                           "Number of client queries sent from \
                                                            the cache",
                                                           labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_expired: register_counter!(opts!("edgedns_client_queries_expired",
                                                            "Number of expired client queries",
                                                            labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_offline: register_counter!(opts!("edgedns_client_queries_offline",
                                                            "Number of client queries answered \
                                                             while upstream resolvers are \
                                                             unresponsive",
                                                            labels!{"handler" => "all",}))
                    .unwrap(),
            client_queries_errors: register_counter!(opts!("edgedns_client_queries_errors",
                                                           "Number of bogus client queries",
                                                           labels!{"handler" => "all",}))
                    .unwrap(),
            inflight_queries:
                register_gauge!(opts!("edgedns_inflight_queries",
                                      "Number of queries currently waiting for a response",
                                      labels!{"handler" => "all",}))
                        .unwrap(),
            upstream_errors: register_counter!(opts!("edgedns_upstream_errors",
                                                     "Number of bogus upstream servers responses",
                                                     labels!{"handler" => "all",}))
                    .unwrap(),
            upstream_sent: register_counter!(opts!("edgedns_upstream_sent",
                                                   "Number of upstream servers queries sent",
                                                   labels!{"handler" => "all",}))
                    .unwrap(),
            upstream_received:
                register_counter!(opts!("edgedns_upstream_received",
                                        "Number of upstream servers responses received",
                                        labels!{"handler" => "all",}))
                        .unwrap(),
            upstream_timeout: register_counter!(opts!("edgedns_upstream_timeout",
                                                      "Number of upstream servers responses \
                                                       having timed out",
                                                      labels!{"handler" => "all",}))
                    .unwrap(),
            upstream_avg_rtt: register_gauge!(opts!("edgedns_upstream_avg_rtt",
                                                    "Average RTT to upstream servers",
                                                    labels!{"handler" => "all",}))
                    .unwrap(),
            upstream_response_sizes: register_histogram!("edgedns_upstream_response_sizes",
                                                         "Response size in bytes.")
                    .unwrap(),
        }
    }
}

impl Default for Varz {
    fn default() -> Self {
        Self::new()
    }
}

impl Default for StartInstant {
    fn default() -> StartInstant {
        StartInstant(Instant::now())
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rust::{ParserAttr, respan};
use rust::Token as rtok;
use rust::BinOpToken as rbtok;
use rust;
use std::str::Chars;
use std::iter::Peekable;

use front::ast::*;
use front::ast::Expression_::*;

pub struct Parser<'a>
{
  rp: rust::Parser<'a>,
  inner_attrs: Vec<rust::Attribute>,
  grammar_name: rust::Ident
}

impl<'a> Parser<'a>
{
  pub fn new(sess: &'a rust::ParseSess,
         cfg: rust::CrateConfig,
         tts: Vec<rust::TokenTree>,
         grammar_name: rust::Ident) -> Parser<'a>
  {
    Parser{
      rp: rust::new_parser_from_tts(sess, cfg, tts),
      inner_attrs: Vec::new(),
      grammar_name: grammar_name
    }
  }

  pub fn parse_grammar(&mut self) -> Grammar {
    let (rules, rust_items) = self.parse_blocks();
    Grammar{name: self.grammar_name, rules: rules, rust_items: rust_items, attributes: self.inner_attrs.to_vec()}
  }

  fn bump(&mut self) {
    self.rp.bump().unwrap()
  }

  fn parse_blocks(&mut self) -> (Vec<Rule>, Vec<RItem>) {
    let mut rules = vec![];
    let mut rust_items = vec![];
    while self.rp.token != rtok::Eof
    {
      self.rp.parse_item().map_or_else(
        || rules.push(self.parse_rule()),
        |item| rust_items.push(item))
    }
    (rules, rust_items)
  }

  fn parse_rule(&mut self) -> Rule {
    let outer_attrs = self.parse_attributes();
    let name = self.parse_rule_decl();
    self.rp.expect(&rtok::Eq).unwrap();
    let body = self.parse_rule_rhs(id_to_string(name.node).as_str());
    Rule{name: name, attributes: outer_attrs, def: body}
  }

  // Outer attributes are attached to the next item.
  // Inner attributes are attached to the englobing item.
  fn parse_attributes(&mut self) -> Vec<rust::Attribute> {
    let inners = self.rp.parse_inner_attributes();
    self.inner_attrs.push_all(inners.as_slice());
    self.rp.parse_outer_attributes()
  }

  fn parse_rule_decl(&mut self) -> rust::SpannedIdent {
    let sp = self.rp.span;
    respan(sp, self.rp.parse_ident().unwrap())
  }

  fn parse_rule_rhs(&mut self, rule_name: &str) -> Box<Expression> {
    self.parse_rule_choice(rule_name)
  }

  fn parse_rule_choice(&mut self, rule_name: &str) -> Box<Expression> {
    let lo = self.rp.span.lo;
    let mut choices = Vec::new();
    loop{
      let seq = self.parse_rule_seq(rule_name);
      choices.push(self.parse_semantic_action_or_ty(seq, rule_name));
      let token = self.rp.token.clone();
      match token {
        rtok::BinOp(rbtok::Slash) => self.bump(),
        _ => break
      }
    }
    let hi = self.rp.last_span.hi;
    if choices.len() == 1 {
      choices.pop().unwrap()
    } else {
      spanned_expr(lo, hi, Choice(choices))
    }
  }

  fn parse_semantic_action_or_ty(&mut self, expr: Box<Expression>, rule_name: &str) -> Box<Expression> {
    let token = self.rp.token.clone();
    match token {
      rtok::Gt => {
        self.bump();
        let fun_name = self.rp.parse_ident().unwrap();
        self.last_respan(SemanticAction(expr, fun_name))
      },
      rtok::RArrow => {
        self.bump();
        self.parse_type(expr, rule_name)
      }
      _ => expr
    }
  }

  // `()` or `(^)`
  fn parse_type(&mut self, mut expr: Box<Expression>, rule_name: &str) -> Box<Expression> {
    let token = self.rp.token.clone();
    match token {
      rtok::OpenDelim(rust::DelimToken::Paren) => {
        self.bump();
        let token = self.rp.token.clone();
        let mut ty = TypeAnnotation::Unit;
        if token == rtok::BinOp(rbtok::Caret) {
          self.bump();
          ty = TypeAnnotation::Invisible;
        }
        self.rp.expect(&rtok::CloseDelim(rust::DelimToken::Paren)).unwrap();
        expr.ty = Some(ty);
        expr
      }
      _ => {
        let span = self.rp.span;
        self.rp.span_err(
          span,
          format!("In rule {}: Unknown token after `->`. Use the arrow to annotate an expression with the unit type `()` or the invisible type `(^)`.",
            rule_name).as_str()
        );
        expr
      }
    }
  }

  fn parse_rule_seq(&mut self, rule_name: &str) -> Box<Expression> {
    let lo = self.rp.span.lo;
    let mut seq = Vec::new();
    while let Some(expr) = self.parse_rule_prefixed(rule_name) {
      seq.push(expr);
    }
    let hi = self.rp.last_span.hi;
    if seq.len() == 0 {
      self.rp.span_err(
        mk_sp(lo, hi),
        format!("In rule {}: must defined at least one expression.",
          rule_name).as_str());
    }
    spanned_expr(lo, hi, Sequence(seq))
  }

  fn parse_rule_prefixed(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    match token {
      rtok::Not => {
        self.parse_prefix(rule_name, |e| NotPredicate(e))
      }
      rtok::BinOp(rbtok::And) => {
        self.parse_prefix(rule_name, |e| AndPredicate(e))
      }
      _ => self.parse_rule_suffixed(rule_name)
    }
  }

  fn parse_prefix<F>(&mut self, rule_name: &str, make_prefix: F) -> Option<Box<Expression>>
   where F: Fn(Box<Expression>) -> ExpressionNode
  {
    let lo = self.rp.span.lo;
    self.bump();
    let expr = match self.parse_rule_suffixed(rule_name) {
      Some(expr) => expr,
      None => {
        let span = self.rp.span;
        self.rp.span_err(
          span,
          format!("In rule {}: A not predicate (`!expr`) is not followed by a \
            valid expression. Do not forget it must be in front of the expression.",
            rule_name).as_str()
        );
        return None
      }
    };
    let hi = self.rp.span.hi;
    Some(spanned_expr(lo, hi, make_prefix(expr)))
  }

  fn parse_rule_suffixed(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let lo = self.rp.span.lo;
    let expr = match self.parse_rule_atom(rule_name){
      Some(expr) => expr,
      None => return None
    };
    let hi = self.rp.span.hi;
    let token = self.rp.token.clone();
    match token {
      rtok::BinOp(rbtok::Star) => {
        self.bump();
        Some(spanned_expr(lo, hi, ZeroOrMore(expr)))
      },
      rtok::BinOp(rbtok::Plus) => {
        self.bump();
        Some(spanned_expr(lo, hi, OneOrMore(expr)))
      },
      rtok::Question => {
        self.bump();
        Some(spanned_expr(lo, hi, Optional(expr)))
      },
      _ => Some(expr)
    }
  }

  fn last_respan(&self, expr: ExpressionNode) -> Box<Expression> {
    respan_expr(self.rp.last_span, expr)
  }

  fn parse_rule_atom(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    if token.is_any_keyword() {
      return None
    }
    match token {
      rtok::Literal(rust::token::Lit::Str_(name),_) => {
        self.bump();
        Some(self.last_respan(StrLiteral(name_to_string(name))))
      },
      rtok::Dot => {
        self.bump();
        Some(self.last_respan(AnySingleChar))
      },
      rtok::OpenDelim(rust::DelimToken::Paren) => {
        self.bump();
        let res = self.parse_rule_rhs(rule_name);
        self.rp.expect(&rtok::CloseDelim(rust::DelimToken::Paren)).unwrap();
        Some(res)
      },
      rtok::Ident(id, _) => {
        if self.is_rule_lhs() { None }
        else {
          self.bump();
          Some(self.last_respan(NonTerminalSymbol(id)))
        }
      },
      rtok::OpenDelim(rust::DelimToken::Bracket) => {
        self.bump();
        let res = self.parse_char_class(rule_name);
        match self.rp.token {
          rtok::CloseDelim(rust::DelimToken::Bracket) => {
            self.bump();
            res
          },
          _ => {
            let span = self.rp.span;
            panic!(self.rp.span_fatal(
              span,
              format!("In rule {}: A character class must always be terminated by `]` \
                and can only contain a string literal (such as in `[\"a-z\"]`",
                rule_name).as_str()
            ));
          }
        }
      },
      _ => { None }
    }
  }

  fn parse_char_class(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    match token {
      rtok::Literal(rust::token::Lit::Str_(name),_) => {
        self.bump();
        let cooked_lit = rust::str_lit(name_to_string(name).as_str());
        self.parse_set_of_char_range(&cooked_lit, rule_name)
      },
      _ => {
        let span = self.rp.span;
        panic!(self.rp.span_fatal(
          span,
          format!("In rule {}: An expected character occurred in this character class. \
            `[` must only be followed by a string literal (such as in `[\"a-z\"]`",
            rule_name).as_str()
        ));
      }
    }
  }

  fn parse_set_of_char_range(&mut self, ranges: &String, rule_name: &str) -> Option<Box<Expression>> {
    let mut ranges = ranges.chars().peekable();
    let mut intervals = vec![];
    match ranges.peek() {
      Some(&sep) if sep == '-' => {
        intervals.push(CharacterInterval{lo: '-', hi: '-'});
        ranges.next();
      }
      _ => ()
    }
    loop {
      match self.parse_char_range(&mut ranges, rule_name) {
        Some(char_set) => intervals.push_all(char_set.as_slice()),
        None => break
      }
    }
    Some(respan_expr(self.rp.span, CharacterClass(CharacterClassExpr{intervals: intervals})))
  }

  fn parse_char_range<'b>(&mut self, ranges: &mut Peekable<Chars<'b>>, rule_name: &str) -> Option<Vec<CharacterInterval>> {
    let mut res = vec![];
    let separator_err = format!(
      "In rule {}: Unexpected separator `-`. Put it in the start or the end if you want \
      to accept it as a character in the set. Otherwise, you should only use it for \
      character intervals as in `[\"a-z\"]`.",
      rule_name);
    let span = self.rp.span;
    let lo = ranges.next();
    // Twisted logic due to the fact that `peek` borrows the ranges...
    let lo = {
      let next = ranges.peek();
      match (lo, next) {
        (Some('-'), Some(_)) => {
          self.rp.span_err(span, separator_err.as_str());
          return None
        },
        (Some(lo), Some(&sep)) if sep == '-' => {
          lo
        },
        (Some(lo), _) => {
          res.push(CharacterInterval{lo: lo, hi: lo}); // If lo == '-', it ends the class, allowed.
          return Some(res)
        }
        (None, _) => return None
      }
    };
    ranges.next();
    match ranges.next() {
      Some('-') => { self.rp.span_err(span, separator_err.as_str()); None }
      Some(hi) => {
        res.push(CharacterInterval{lo: lo, hi: hi});
        Some(res)
      }
      None => {
        res.push(CharacterInterval{lo:lo, hi:lo});
        res.push(CharacterInterval{lo:'-', hi: '-'});
        Some(res)
      }
    }
  }

  fn is_rule_lhs(&mut self) -> bool {
    self.rp.look_ahead(1, |t| match t { &rtok::Eq => true, _ => false})
  }
}
<commit_msg>[Front-end][Bug] Inner attributes are now always considered to be Oak one's. Related to #45.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rust::{ParserAttr, respan};
use rust::Token as rtok;
use rust::BinOpToken as rbtok;
use rust;
use std::str::Chars;
use std::iter::Peekable;

use front::ast::*;
use front::ast::Expression_::*;

pub struct Parser<'a>
{
  rp: rust::Parser<'a>,
  inner_attrs: Vec<rust::Attribute>,
  grammar_name: rust::Ident
}

impl<'a> Parser<'a>
{
  pub fn new(sess: &'a rust::ParseSess,
         cfg: rust::CrateConfig,
         tts: Vec<rust::TokenTree>,
         grammar_name: rust::Ident) -> Parser<'a>
  {
    Parser{
      rp: rust::new_parser_from_tts(sess, cfg, tts),
      inner_attrs: Vec::new(),
      grammar_name: grammar_name
    }
  }

  pub fn parse_grammar(&mut self) -> Grammar {
    let (rules, rust_items) = self.parse_blocks();
    Grammar{name: self.grammar_name, rules: rules, rust_items: rust_items, attributes: self.inner_attrs.to_vec()}
  }

  fn bump(&mut self) {
    self.rp.bump().unwrap()
  }

  fn parse_blocks(&mut self) -> (Vec<Rule>, Vec<RItem>) {
    let mut rules = vec![];
    let mut rust_items = vec![];
    while self.rp.token != rtok::Eof
    {
      self.parse_inner_attributes();
      self.rp.parse_item().map_or_else(
        || rules.push(self.parse_rule()),
        |item| rust_items.push(item))
    }
    (rules, rust_items)
  }

  fn parse_rule(&mut self) -> Rule {
    let outer_attrs = self.rp.parse_outer_attributes();
    let name = self.parse_rule_decl();
    self.rp.expect(&rtok::Eq).unwrap();
    let body = self.parse_rule_rhs(id_to_string(name.node).as_str());
    Rule{name: name, attributes: outer_attrs, def: body}
  }

  fn parse_inner_attributes(&mut self) {
    let inners = self.rp.parse_inner_attributes();
    self.inner_attrs.push_all(inners.as_slice());
  }

  fn parse_rule_decl(&mut self) -> rust::SpannedIdent {
    let sp = self.rp.span;
    respan(sp, self.rp.parse_ident().unwrap())
  }

  fn parse_rule_rhs(&mut self, rule_name: &str) -> Box<Expression> {
    self.parse_rule_choice(rule_name)
  }

  fn parse_rule_choice(&mut self, rule_name: &str) -> Box<Expression> {
    let lo = self.rp.span.lo;
    let mut choices = Vec::new();
    loop{
      let seq = self.parse_rule_seq(rule_name);
      choices.push(self.parse_semantic_action_or_ty(seq, rule_name));
      let token = self.rp.token.clone();
      match token {
        rtok::BinOp(rbtok::Slash) => self.bump(),
        _ => break
      }
    }
    let hi = self.rp.last_span.hi;
    if choices.len() == 1 {
      choices.pop().unwrap()
    } else {
      spanned_expr(lo, hi, Choice(choices))
    }
  }

  fn parse_semantic_action_or_ty(&mut self, expr: Box<Expression>, rule_name: &str) -> Box<Expression> {
    let token = self.rp.token.clone();
    match token {
      rtok::Gt => {
        self.bump();
        let fun_name = self.rp.parse_ident().unwrap();
        self.last_respan(SemanticAction(expr, fun_name))
      },
      rtok::RArrow => {
        self.bump();
        self.parse_type(expr, rule_name)
      }
      _ => expr
    }
  }

  // `()` or `(^)`
  fn parse_type(&mut self, mut expr: Box<Expression>, rule_name: &str) -> Box<Expression> {
    let token = self.rp.token.clone();
    match token {
      rtok::OpenDelim(rust::DelimToken::Paren) => {
        self.bump();
        let token = self.rp.token.clone();
        let mut ty = TypeAnnotation::Unit;
        if token == rtok::BinOp(rbtok::Caret) {
          self.bump();
          ty = TypeAnnotation::Invisible;
        }
        self.rp.expect(&rtok::CloseDelim(rust::DelimToken::Paren)).unwrap();
        expr.ty = Some(ty);
        expr
      }
      _ => {
        let span = self.rp.span;
        self.rp.span_err(
          span,
          format!("In rule {}: Unknown token after `->`. Use the arrow to annotate an expression with the unit type `()` or the invisible type `(^)`.",
            rule_name).as_str()
        );
        expr
      }
    }
  }

  fn parse_rule_seq(&mut self, rule_name: &str) -> Box<Expression> {
    let lo = self.rp.span.lo;
    let mut seq = Vec::new();
    while let Some(expr) = self.parse_rule_prefixed(rule_name) {
      seq.push(expr);
    }
    let hi = self.rp.last_span.hi;
    if seq.len() == 0 {
      self.rp.span_err(
        mk_sp(lo, hi),
        format!("In rule {}: must defined at least one expression.",
          rule_name).as_str());
    }
    spanned_expr(lo, hi, Sequence(seq))
  }

  fn parse_rule_prefixed(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    match token {
      rtok::Not => {
        self.parse_prefix(rule_name, |e| NotPredicate(e))
      }
      rtok::BinOp(rbtok::And) => {
        self.parse_prefix(rule_name, |e| AndPredicate(e))
      }
      _ => self.parse_rule_suffixed(rule_name)
    }
  }

  fn parse_prefix<F>(&mut self, rule_name: &str, make_prefix: F) -> Option<Box<Expression>>
   where F: Fn(Box<Expression>) -> ExpressionNode
  {
    let lo = self.rp.span.lo;
    self.bump();
    let expr = match self.parse_rule_suffixed(rule_name) {
      Some(expr) => expr,
      None => {
        let span = self.rp.span;
        self.rp.span_err(
          span,
          format!("In rule {}: A not predicate (`!expr`) is not followed by a \
            valid expression. Do not forget it must be in front of the expression.",
            rule_name).as_str()
        );
        return None
      }
    };
    let hi = self.rp.span.hi;
    Some(spanned_expr(lo, hi, make_prefix(expr)))
  }

  fn parse_rule_suffixed(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let lo = self.rp.span.lo;
    let expr = match self.parse_rule_atom(rule_name){
      Some(expr) => expr,
      None => return None
    };
    let hi = self.rp.span.hi;
    let token = self.rp.token.clone();
    match token {
      rtok::BinOp(rbtok::Star) => {
        self.bump();
        Some(spanned_expr(lo, hi, ZeroOrMore(expr)))
      },
      rtok::BinOp(rbtok::Plus) => {
        self.bump();
        Some(spanned_expr(lo, hi, OneOrMore(expr)))
      },
      rtok::Question => {
        self.bump();
        Some(spanned_expr(lo, hi, Optional(expr)))
      },
      _ => Some(expr)
    }
  }

  fn last_respan(&self, expr: ExpressionNode) -> Box<Expression> {
    respan_expr(self.rp.last_span, expr)
  }

  fn parse_rule_atom(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    if token.is_any_keyword() {
      return None
    }
    match token {
      rtok::Literal(rust::token::Lit::Str_(name),_) => {
        self.bump();
        Some(self.last_respan(StrLiteral(name_to_string(name))))
      },
      rtok::Dot => {
        self.bump();
        Some(self.last_respan(AnySingleChar))
      },
      rtok::OpenDelim(rust::DelimToken::Paren) => {
        self.bump();
        let res = self.parse_rule_rhs(rule_name);
        self.rp.expect(&rtok::CloseDelim(rust::DelimToken::Paren)).unwrap();
        Some(res)
      },
      rtok::Ident(id, _) => {
        if self.is_rule_lhs() { None }
        else {
          self.bump();
          Some(self.last_respan(NonTerminalSymbol(id)))
        }
      },
      rtok::OpenDelim(rust::DelimToken::Bracket) => {
        self.bump();
        let res = self.parse_char_class(rule_name);
        match self.rp.token {
          rtok::CloseDelim(rust::DelimToken::Bracket) => {
            self.bump();
            res
          },
          _ => {
            let span = self.rp.span;
            panic!(self.rp.span_fatal(
              span,
              format!("In rule {}: A character class must always be terminated by `]` \
                and can only contain a string literal (such as in `[\"a-z\"]`",
                rule_name).as_str()
            ));
          }
        }
      },
      _ => { None }
    }
  }

  fn parse_char_class(&mut self, rule_name: &str) -> Option<Box<Expression>> {
    let token = self.rp.token.clone();
    match token {
      rtok::Literal(rust::token::Lit::Str_(name),_) => {
        self.bump();
        let cooked_lit = rust::str_lit(name_to_string(name).as_str());
        self.parse_set_of_char_range(&cooked_lit, rule_name)
      },
      _ => {
        let span = self.rp.span;
        panic!(self.rp.span_fatal(
          span,
          format!("In rule {}: An expected character occurred in this character class. \
            `[` must only be followed by a string literal (such as in `[\"a-z\"]`",
            rule_name).as_str()
        ));
      }
    }
  }

  fn parse_set_of_char_range(&mut self, ranges: &String, rule_name: &str) -> Option<Box<Expression>> {
    let mut ranges = ranges.chars().peekable();
    let mut intervals = vec![];
    match ranges.peek() {
      Some(&sep) if sep == '-' => {
        intervals.push(CharacterInterval{lo: '-', hi: '-'});
        ranges.next();
      }
      _ => ()
    }
    loop {
      match self.parse_char_range(&mut ranges, rule_name) {
        Some(char_set) => intervals.push_all(char_set.as_slice()),
        None => break
      }
    }
    Some(respan_expr(self.rp.span, CharacterClass(CharacterClassExpr{intervals: intervals})))
  }

  fn parse_char_range<'b>(&mut self, ranges: &mut Peekable<Chars<'b>>, rule_name: &str) -> Option<Vec<CharacterInterval>> {
    let mut res = vec![];
    let separator_err = format!(
      "In rule {}: Unexpected separator `-`. Put it in the start or the end if you want \
      to accept it as a character in the set. Otherwise, you should only use it for \
      character intervals as in `[\"a-z\"]`.",
      rule_name);
    let span = self.rp.span;
    let lo = ranges.next();
    // Twisted logic due to the fact that `peek` borrows the ranges...
    let lo = {
      let next = ranges.peek();
      match (lo, next) {
        (Some('-'), Some(_)) => {
          self.rp.span_err(span, separator_err.as_str());
          return None
        },
        (Some(lo), Some(&sep)) if sep == '-' => {
          lo
        },
        (Some(lo), _) => {
          res.push(CharacterInterval{lo: lo, hi: lo}); // If lo == '-', it ends the class, allowed.
          return Some(res)
        }
        (None, _) => return None
      }
    };
    ranges.next();
    match ranges.next() {
      Some('-') => { self.rp.span_err(span, separator_err.as_str()); None }
      Some(hi) => {
        res.push(CharacterInterval{lo: lo, hi: hi});
        Some(res)
      }
      None => {
        res.push(CharacterInterval{lo:lo, hi:lo});
        res.push(CharacterInterval{lo:'-', hi: '-'});
        Some(res)
      }
    }
  }

  fn is_rule_lhs(&mut self) -> bool {
    self.rp.look_ahead(1, |t| match t { &rtok::Eq => true, _ => false})
  }
}
<|endoftext|>


<commit_before>/// Black-Scholes formula parameters
/// s0 - underlying price (USD per share)
/// x - strike price (USD per share)
/// sigma - volatility (%)
/// r - continuously compounded risk-free interest rate (%)
/// q - continously compounded dividend yield (%)
/// t - time to expiration (% of year)
use std::f64::consts::E;
use std::f64::consts::PI;
use stats::cnd;

pub fn delta_call(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    let cnd = cnd(d1);
    let e = E.powf(-(q * t));
    return e * cnd;
}

pub fn delta_put(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    let cnd = cnd(d1);
    let e = E.powf(-(q * t));
    return e * (cnd - 1.0);
}

pub fn gamma(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    return gamma_d1(s0, t, q, sigma, d1);
}

pub fn gamma_d1(s0: f64, t: f64, q: f64, sigma: f64, d1: f64) -> f64 {
    let arg1 = E.powf(-(q * t)) / (s0 * sigma * (t.sqrt()));
    let arg2 = one_over_sqrt_pi();
    let arg3 = E.powf((-d1).powf(2.0)) / 2.0;
    return arg1 * arg2 * arg3;
}

pub fn vega(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    return vega_d1(s0, t, q, d1);
}

pub fn vega_d1(s0: f64, t: f64, q: f64, d1: f64) -> f64 {
    let mult1 = (1.0 / 100.0) * s0 * E.powf(-(q * t)) * t.sqrt();
    let mult2 = one_over_sqrt_pi();
    let mult3 = E.powf((-d1.powf(2.0) / 2.0));
    return mult1 * mult2 * mult3;
}

fn one_over_sqrt_pi() -> f64 {
    return 1.0 / (2.0 * PI).sqrt();
}

pub fn d1(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let ln = (s0 / x).ln();
    let t_num = t * (r - q + (sigma.powf(2f64) / 2f64));
    return (ln + t_num) / (sigma * t.sqrt());
}

// TODO Add overload for providing d1
pub fn d2(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    return d1 - (t.sqrt() * sigma);
}

#[cfg(test)]
mod tests {

    use greeks::*;

    const UNDERLYING: f64 = 64.68;
    const STRIKE: f64 = 65.00;
    const VOL: f64 = 0.5051;
    const INTEREST_RATE: f64 = 0.0150;
    const DIV_YIELD: f64 = 0.0210;
    const TIME_TO_EXPIRY: f64 = 23.0 / 365.0;

    const E_D1: f64 = 0.0214;
    const E_D2: f64 = -0.1053;
    const E_CALL_DELTA: f64 = 0.5079;
    const E_PUT_DELTA: f64 = -0.4908;
    const E_GAMMA: f64 = 0.0243;
    const E_VEGA: f64 = 0.0647;

    #[test]
    fn test_d1() {
        let d1 = d1(UNDERLYING,
                    STRIKE,
                    TIME_TO_EXPIRY,
                    INTEREST_RATE,
                    DIV_YIELD,
                    VOL);
        println!("{}", d1);
        let abs = (d1 - E_D1).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_d2() {
        let d2 = d2(UNDERLYING,
                    STRIKE,
                    TIME_TO_EXPIRY,
                    INTEREST_RATE,
                    DIV_YIELD,
                    VOL);
        let abs = (d2 - E_D2).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_delta_call() {
        let call_delta = delta_call(UNDERLYING,
                                    STRIKE,
                                    TIME_TO_EXPIRY,
                                    INTEREST_RATE,
                                    DIV_YIELD,
                                    VOL);
        let abs = (call_delta - E_CALL_DELTA).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_delta_put() {
        let put_delta = delta_put(UNDERLYING,
                                  STRIKE,
                                  TIME_TO_EXPIRY,
                                  INTEREST_RATE,
                                  DIV_YIELD,
                                  VOL);
        let abs = (put_delta - E_PUT_DELTA).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_gamma() {
        let gamma = gamma(UNDERLYING,
                          STRIKE,
                          TIME_TO_EXPIRY,
                          INTEREST_RATE,
                          DIV_YIELD,
                          VOL);
        let abs = (gamma - E_GAMMA).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_vega() {
        let vega = vega(UNDERLYING,
                        STRIKE,
                        TIME_TO_EXPIRY,
                        INTEREST_RATE,
                        DIV_YIELD,
                        VOL);
        let abs = (vega - E_VEGA).abs();
        assert!(abs < 0.001);
    }
}
<commit_msg>added theta and associated tests<commit_after>/// Black-Scholes formula parameters
/// s0 - underlying price (USD per share)
/// x - strike price (USD per share)
/// sigma - volatility (%)
/// r - continuously compounded risk-free interest rate (%)
/// q - continously compounded dividend yield (%)
/// t - time to expiration (% of year)
use std::f64::consts::E;
use std::f64::consts::PI;
use stats::cnd;

pub fn delta_call(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    let cnd = cnd(d1);
    let e = E.powf(-(q * t));
    return e * cnd;
}

pub fn delta_put(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    let cnd = cnd(d1);
    let e = E.powf(-(q * t));
    return e * (cnd - 1.0);
}

pub fn gamma(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    return gamma_d1(s0, t, q, sigma, d1);
}

pub fn gamma_d1(s0: f64, t: f64, q: f64, sigma: f64, d1: f64) -> f64 {
    let arg1 = E.powf(-(q * t)) / (s0 * sigma * (t.sqrt()));
    let arg2 = one_over_sqrt_pi();
    let arg3 = E.powf((-d1).powf(2.0)) / 2.0;
    return arg1 * arg2 * arg3;
}

pub fn theta_call(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64, days_per_year: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    let arg1 = theta_arg_1(s0, t, q, sigma, d1);
    let d2 = d2_d1(t, sigma, d1);
    let arg2 = theta_arg_2(x, t, r, q, sigma, d2);
    let arg3 = theta_arg_3(s0, t, q, d1);
    return (1.0 / days_per_year) * (arg1 - arg2 + arg3);
}

pub fn theta_put(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64, days_per_year: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    let arg1 = theta_arg_1(s0, t, q, sigma, d1);
    let d2 = d2_d1(t, sigma, d1);
    let arg2 = theta_arg_2(x, t, r, q, sigma, -d2); // d2 is negative for a put
    let arg3 = theta_arg_3(s0, t, q, -d1); // d1 is negative for a put
    return (1.0 / days_per_year) * (arg1 + arg2 - arg3);
}

fn theta_arg_1(s0: f64, t: f64, q: f64, sigma: f64, d1: f64) -> f64 {
    return -(((s0 * sigma * E.powf(-q * t)) / (2.0 * t.sqrt())) * one_over_sqrt_pi() *
             E.powf((-d1.powf(2.0)) / 2.0));
}

fn theta_arg_2(x: f64, t: f64, r: f64, q: f64, sigma: f64, d2: f64) -> f64 {
    return r * x * E.powf(-r * t) * cnd(d2);
}

fn theta_arg_3(s0: f64, t: f64, q: f64, d1: f64) -> f64 {
    return q * s0 * E.powf(-q * t) * cnd(d1);
}

pub fn vega(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    return vega_d1(s0, t, q, d1);
}

pub fn vega_d1(s0: f64, t: f64, q: f64, d1: f64) -> f64 {
    let mult1 = (1.0 / 100.0) * s0 * E.powf(-(q * t)) * t.sqrt();
    let mult2 = one_over_sqrt_pi();
    let mult3 = E.powf((-d1.powf(2.0) / 2.0));
    return mult1 * mult2 * mult3;
}

pub fn rho_call(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d2_cnd = cnd(d2(s0, x, t, r, q, sigma));
    return (1.0 / 100.0) * x * t * E.powf(-r * t) * d2_cnd;
}

pub fn rho_put(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let neg_d2_cnd = cnd(-d2(s0, x, t, r, q, sigma));
    return -(1.0 / 100.0) * x * t * E.powf(-r * t) * neg_d2_cnd;
}

fn one_over_sqrt_pi() -> f64 {
    return 1.0 / (2.0 * PI).sqrt();
}

pub fn d1(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let ln = (s0 / x).ln();
    let t_num = t * (r - q + (sigma.powf(2f64) / 2f64));
    return (ln + t_num) / (sigma * t.sqrt());
}

// TODO Add overload for providing d1
pub fn d2(s0: f64, x: f64, t: f64, r: f64, q: f64, sigma: f64) -> f64 {
    let d1 = d1(s0, x, t, r, q, sigma);
    return d1 - (t.sqrt() * sigma);
}

pub fn d2_d1(t: f64, sigma: f64, d1: f64) -> f64 {
    return d1 - (t.sqrt() * sigma);
}

#[cfg(test)]
mod tests {

    use greeks::*;

    const UNDERLYING: f64 = 64.68;
    const STRIKE: f64 = 65.00;
    const VOL: f64 = 0.5051;
    const INTEREST_RATE: f64 = 0.0150;
    const DIV_YIELD: f64 = 0.0210;
    const DAYS_PER_YEAR: f64 = 365.0;
    const TIME_TO_EXPIRY: f64 = 23.0 / DAYS_PER_YEAR;

    const E_D1: f64 = 0.0214;
    const E_D2: f64 = -0.1053;
    const E_CALL_DELTA: f64 = 0.5079;
    const E_PUT_DELTA: f64 = -0.4908;
    const E_GAMMA: f64 = 0.0243;
    const E_THETA_CALL: f64 = -0.0703;
    const E_THETA_PUT: f64 = -0.0714;
    const E_VEGA: f64 = 0.0647;
    const E_RHO_CALL: f64 = 0.0187;
    const E_RHO_PUT: f64 = -0.0222;

    #[test]
    fn test_d1() {
        let d1 = d1(UNDERLYING,
                    STRIKE,
                    TIME_TO_EXPIRY,
                    INTEREST_RATE,
                    DIV_YIELD,
                    VOL);
        println!("{}", d1);
        let abs = (d1 - E_D1).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_d2() {
        let d2 = d2(UNDERLYING,
                    STRIKE,
                    TIME_TO_EXPIRY,
                    INTEREST_RATE,
                    DIV_YIELD,
                    VOL);
        let abs = (d2 - E_D2).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_delta_call() {
        let call_delta = delta_call(UNDERLYING,
                                    STRIKE,
                                    TIME_TO_EXPIRY,
                                    INTEREST_RATE,
                                    DIV_YIELD,
                                    VOL);
        let abs = (call_delta - E_CALL_DELTA).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_delta_put() {
        let put_delta = delta_put(UNDERLYING,
                                  STRIKE,
                                  TIME_TO_EXPIRY,
                                  INTEREST_RATE,
                                  DIV_YIELD,
                                  VOL);
        let abs = (put_delta - E_PUT_DELTA).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_gamma() {
        let gamma = gamma(UNDERLYING,
                          STRIKE,
                          TIME_TO_EXPIRY,
                          INTEREST_RATE,
                          DIV_YIELD,
                          VOL);
        let abs = (gamma - E_GAMMA).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_theta_call() {
        let theta_call = theta_call(UNDERLYING,
                                    STRIKE,
                                    TIME_TO_EXPIRY,
                                    INTEREST_RATE,
                                    DIV_YIELD,
                                    VOL,
                                    DAYS_PER_YEAR);
        let abs = (theta_call - E_THETA_CALL).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_theta_put() {
        let theta_put = theta_put(UNDERLYING,
                                  STRIKE,
                                  TIME_TO_EXPIRY,
                                  INTEREST_RATE,
                                  DIV_YIELD,
                                  VOL,
                                  DAYS_PER_YEAR);
        println!("{}", theta_put);
        let abs = (theta_put - E_THETA_PUT).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_vega() {
        let vega = vega(UNDERLYING,
                        STRIKE,
                        TIME_TO_EXPIRY,
                        INTEREST_RATE,
                        DIV_YIELD,
                        VOL);
        let abs = (vega - E_VEGA).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_rho_call() {
        let rho_call = rho_call(UNDERLYING,
                                STRIKE,
                                TIME_TO_EXPIRY,
                                INTEREST_RATE,
                                DIV_YIELD,
                                VOL);
        let abs = (rho_call - E_RHO_CALL).abs();
        assert!(abs < 0.001);
    }

    #[test]
    fn test_rho_put() {
        let rho_put = rho_put(UNDERLYING,
                              STRIKE,
                              TIME_TO_EXPIRY,
                              INTEREST_RATE,
                              DIV_YIELD,
                              VOL);
        let abs = (rho_put - E_RHO_PUT).abs();
        assert!(abs < 0.001);
    }

}
<|endoftext|>