<commit_before>use crate::{
    error::{ParseError, ParseResult, StreamError},
    lib::fmt,
    stream::{
        IteratorStream, Positioned, RangeStreamOnce, ResetStream, SliceStream, StreamErrorFor,
        StreamOnce,
    },
};

#[cfg(feature = "std")]
use crate::stream::ReadStream;

/// Trait for tracking the current position of a `Stream`.
pub trait Positioner<Item> {
    /// The type which keeps track of the position
    type Position: Clone + Ord;
    /// Returns the current position
    fn position(&self) -> Self::Position;
    /// Updates the position given that `token` has been taken from the stream
    fn update(&mut self, token: &Item);
}

/// Trait for tracking the current position of a `RangeStream`.
pub trait RangePositioner<Item, Range>: Positioner<Item> {
    /// Updates the position given that `range` has been taken from the stream
    fn update_range(&mut self, range: &Range);
}

/// Defines a default `Positioner` type for a particular `Stream` type.
pub trait DefaultPositioned {
    type Positioner: Default;
}

impl<'a> DefaultPositioned for &'a str {
    type Positioner = SourcePosition;
}

impl<'a, T> DefaultPositioned for &'a [T] {
    type Positioner = IndexPositioner;
}

impl<'a, T> DefaultPositioned for SliceStream<'a, T> {
    type Positioner = IndexPositioner;
}

impl<T> DefaultPositioned for IteratorStream<T> {
    type Positioner = IndexPositioner;
}

#[cfg(feature = "std")]
impl<R> DefaultPositioned for ReadStream<R> {
    type Positioner = IndexPositioner;
}

/// The `Stream<Input>` struct maintains the current position in the stream `Input` using
/// the `Positioner` trait to track the position.
///
/// ```
/// # #![cfg(feature = "std")]
/// # extern crate combine;
/// # use combine::*;
/// # use combine::stream::easy;
/// # use combine::stream::position;
/// # fn main() {
///     let result = token(b'9')
///         .message("Not a nine")
///         .easy_parse(position::Stream::new(&b"8"[..]));
///     assert_eq!(result, Err(easy::Errors {
///         position: 0,
///         errors: vec![
///             easy::Error::Unexpected(b'8'.into()),
///             easy::Error::Expected(b'9'.into()),
///             easy::Error::Message("Not a nine".into())
///         ]
///     }));
/// # }
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct Stream<Input, X> {
    /// The input stream used when items are requested
    pub input: Input,
    /// The positioner used to update the current position
    pub positioner: X,
}

impl<Input, X> Stream<Input, X>
where
    Input: StreamOnce,
    X: Positioner<Input::Token>,
{
    /// Creates a new `Stream<Input, X>` from an input stream and a positioner.
    pub fn with_positioner(input: Input, positioner: X) -> Stream<Input, X> {
        Stream { input, positioner }
    }
}

impl<Input> Stream<Input, Input::Positioner>
where
    Input: StreamOnce + DefaultPositioned,
    Input::Positioner: Positioner<Input::Token>,
{
    /// Creates a new `Stream<Input, X>` from an input stream and its default positioner.
    pub fn new(input: Input) -> Stream<Input, Input::Positioner> {
        Stream::with_positioner(input, Input::Positioner::default())
    }
}

impl<Input, X, E> Positioned for Stream<Input, X>
where
    Input: StreamOnce,
    X: Positioner<Input::Token>,
    E: StreamError<Input::Token, Input::Range>,
    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = E>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = E>,
{
    #[inline]
    fn position(&self) -> Self::Position {
        self.positioner.position()
    }
}

impl<Input, X, S> StreamOnce for Stream<Input, X>
where
    Input: StreamOnce,
    X: Positioner<Input::Token>,
    S: StreamError<Input::Token, Input::Range>,
    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
{
    type Token = Input::Token;
    type Range = Input::Range;
    type Position = X::Position;
    type Error = Input::Error;

    #[inline]
    fn uncons(&mut self) -> Result<Input::Token, StreamErrorFor<Self>> {
        self.input.uncons().map(|c| {
            self.positioner.update(&c);
            c
        })
    }

    fn is_partial(&self) -> bool {
        self.input.is_partial()
    }
}

/// The `IndexPositioner<Item, Range>` struct maintains the current index into the stream `Input`.  The
/// initial index is index 0.  Each `Item` consumed increments the index by 1; each `range` consumed
/// increments the position by `range.len()`.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct IndexPositioner(usize);

impl<Item> Positioner<Item> for IndexPositioner
where
    Item: PartialEq + Clone,
{
    type Position = usize;

    #[inline]
    fn position(&self) -> usize {
        self.0
    }

    #[inline]
    fn update(&mut self, _item: &Item) {
        self.0 += 1
    }
}

impl IndexPositioner {
    pub fn new() -> IndexPositioner {
        IndexPositioner::new_with_position(0)
    }

    pub fn new_with_position(position: usize) -> IndexPositioner {
        IndexPositioner(position)
    }
}

impl<Item, Range> RangePositioner<Item, Range> for IndexPositioner
where
    Item: PartialEq + Clone,
    Range: PartialEq + Clone + crate::stream::Range,
{
    fn update_range(&mut self, range: &Range) {
        self.0 += range.len()
    }
}

/// Struct which represents a position in a source file.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct SourcePosition {
    /// Current line of the input
    pub line: i32,
    /// Current column of the input
    pub column: i32,
}

impl Default for SourcePosition {
    fn default() -> Self {
        SourcePosition { line: 1, column: 1 }
    }
}

impl fmt::Display for SourcePosition {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "line: {}, column: {}", self.line, self.column)
    }
}

impl SourcePosition {
    pub fn new() -> Self {
        SourcePosition::default()
    }
}

impl Positioner<char> for SourcePosition {
    type Position = SourcePosition;

    #[inline]
    fn position(&self) -> SourcePosition {
        self.clone()
    }

    #[inline]
    fn update(&mut self, token: &char) {
        self.column += 1;
        if *token == '\n' {
            self.column = 1;
            self.line += 1;
        }
    }
}

impl<'a> RangePositioner<char, &'a str> for SourcePosition {
    fn update_range(&mut self, range: &&'a str) {
        for c in range.chars() {
            self.update(&c);
        }
    }
}

impl<Input, X, S> RangeStreamOnce for Stream<Input, X>
where
    Input: RangeStreamOnce,
    X: Clone + RangePositioner<Input::Token, Input::Range>,
    S: StreamError<Input::Token, Input::Range>,
    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
    Input::Position: Clone + Ord,
{
    #[inline]
    fn uncons_range(&mut self, size: usize) -> Result<Input::Range, StreamErrorFor<Self>> {
        self.input.uncons_range(size).map(|range| {
            self.positioner.update_range(&range);
            range
        })
    }

    #[inline]
    fn uncons_while<F>(&mut self, mut predicate: F) -> Result<Input::Range, StreamErrorFor<Self>>
    where
        F: FnMut(Input::Token) -> bool,
    {
        let positioner = &mut self.positioner;
        self.input.uncons_while(|t| {
            if predicate(t.clone()) {
                positioner.update(&t);
                true
            } else {
                false
            }
        })
    }

    #[inline]
    fn uncons_while1<F>(
        &mut self,
        mut predicate: F,
    ) -> ParseResult<Self::Range, StreamErrorFor<Self>>
    where
        F: FnMut(Self::Token) -> bool,
    {
        let positioner = &mut self.positioner;
        self.input.uncons_while1(|t| {
            if predicate(t.clone()) {
                positioner.update(&t);
                true
            } else {
                false
            }
        })
    }

    #[inline]
    fn distance(&self, end: &Self::Checkpoint) -> usize {
        self.input.distance(&end.input)
    }

    fn range(&self) -> Self::Range {
        self.input.range()
    }
}

impl<Input, X, S> ResetStream for Stream<Input, X>
where
    Input: ResetStream,
    X: Clone + Positioner<Input::Token>,
    S: StreamError<Input::Token, Input::Range>,
    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
{
    type Checkpoint = Stream<Input::Checkpoint, X>;
    fn checkpoint(&self) -> Self::Checkpoint {
        Stream {
            input: self.input.checkpoint(),
            positioner: self.positioner.clone(),
        }
    }
    fn reset(&mut self, checkpoint: Self::Checkpoint) -> Result<(), Self::Error> {
        self.input.reset(checkpoint.input)?;
        self.positioner = checkpoint.positioner;
        Ok(())
    }
}

#[cfg(all(feature = "std", test))]
mod tests {

    use crate::Parser;

    use super::*;

    #[test]
    fn test_positioner() {
        let input = ["a".to_string(), "b".to_string()];
        let mut parser = crate::any();
        let result = parser.parse(Stream::new(&input[..]));
        assert_eq!(
            result,
            Ok((
                "a".to_string(),
                Stream::with_positioner(
                    &["b".to_string()][..],
                    IndexPositioner::new_with_position(1)
                )
            ))
        );
    }

    #[test]
    fn test_range_positioner() {
        let input = ["a".to_string(), "b".to_string(), "c".to_string()];
        let mut parser = crate::parser::range::take(2);
        let result = parser.parse(Stream::new(&input[..]));
        assert_eq!(
            result,
            Ok((
                &["a".to_string(), "b".to_string()][..],
                Stream::with_positioner(
                    &["c".to_string()][..],
                    IndexPositioner::new_with_position(2)
                )
            ))
        );
    }
}
<commit_msg>implement support for SourcePosition to work on u8 streams<commit_after>use crate::{
    error::{ParseError, ParseResult, StreamError},
    lib::fmt,
    stream::{
        IteratorStream, Positioned, RangeStreamOnce, ResetStream, SliceStream, StreamErrorFor,
        StreamOnce,
    },
};

#[cfg(feature = "std")]
use crate::stream::ReadStream;

/// Trait for tracking the current position of a `Stream`.
pub trait Positioner<Item> {
    /// The type which keeps track of the position
    type Position: Clone + Ord;
    /// Returns the current position
    fn position(&self) -> Self::Position;
    /// Updates the position given that `token` has been taken from the stream
    fn update(&mut self, token: &Item);
}

/// Trait for tracking the current position of a `RangeStream`.
pub trait RangePositioner<Item, Range>: Positioner<Item> {
    /// Updates the position given that `range` has been taken from the stream
    fn update_range(&mut self, range: &Range);
}

/// Defines a default `Positioner` type for a particular `Stream` type.
pub trait DefaultPositioned {
    type Positioner: Default;
}

impl<'a> DefaultPositioned for &'a str {
    type Positioner = SourcePosition;
}

impl<'a, T> DefaultPositioned for &'a [T] {
    type Positioner = IndexPositioner;
}

impl<'a, T> DefaultPositioned for SliceStream<'a, T> {
    type Positioner = IndexPositioner;
}

impl<T> DefaultPositioned for IteratorStream<T> {
    type Positioner = IndexPositioner;
}

#[cfg(feature = "std")]
impl<R> DefaultPositioned for ReadStream<R> {
    type Positioner = IndexPositioner;
}

/// The `Stream<Input>` struct maintains the current position in the stream `Input` using
/// the `Positioner` trait to track the position.
///
/// ```
/// # #![cfg(feature = "std")]
/// # extern crate combine;
/// # use combine::*;
/// # use combine::stream::easy;
/// # use combine::stream::position;
/// # fn main() {
///     let result = token(b'9')
///         .message("Not a nine")
///         .easy_parse(position::Stream::new(&b"8"[..]));
///     assert_eq!(result, Err(easy::Errors {
///         position: 0,
///         errors: vec![
///             easy::Error::Unexpected(b'8'.into()),
///             easy::Error::Expected(b'9'.into()),
///             easy::Error::Message("Not a nine".into())
///         ]
///     }));
/// # }
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct Stream<Input, X> {
    /// The input stream used when items are requested
    pub input: Input,
    /// The positioner used to update the current position
    pub positioner: X,
}

impl<Input, X> Stream<Input, X>
where
    Input: StreamOnce,
    X: Positioner<Input::Token>,
{
    /// Creates a new `Stream<Input, X>` from an input stream and a positioner.
    pub fn with_positioner(input: Input, positioner: X) -> Stream<Input, X> {
        Stream { input, positioner }
    }
}

impl<Input> Stream<Input, Input::Positioner>
where
    Input: StreamOnce + DefaultPositioned,
    Input::Positioner: Positioner<Input::Token>,
{
    /// Creates a new `Stream<Input, X>` from an input stream and its default positioner.
    pub fn new(input: Input) -> Stream<Input, Input::Positioner> {
        Stream::with_positioner(input, Input::Positioner::default())
    }
}

impl<Input, X, E> Positioned for Stream<Input, X>
where
    Input: StreamOnce,
    X: Positioner<Input::Token>,
    E: StreamError<Input::Token, Input::Range>,
    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = E>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = E>,
{
    #[inline]
    fn position(&self) -> Self::Position {
        self.positioner.position()
    }
}

impl<Input, X, S> StreamOnce for Stream<Input, X>
where
    Input: StreamOnce,
    X: Positioner<Input::Token>,
    S: StreamError<Input::Token, Input::Range>,
    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
{
    type Token = Input::Token;
    type Range = Input::Range;
    type Position = X::Position;
    type Error = Input::Error;

    #[inline]
    fn uncons(&mut self) -> Result<Input::Token, StreamErrorFor<Self>> {
        self.input.uncons().map(|c| {
            self.positioner.update(&c);
            c
        })
    }

    fn is_partial(&self) -> bool {
        self.input.is_partial()
    }
}

/// The `IndexPositioner<Item, Range>` struct maintains the current index into the stream `Input`.  The
/// initial index is index 0.  Each `Item` consumed increments the index by 1; each `range` consumed
/// increments the position by `range.len()`.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct IndexPositioner(usize);

impl<Item> Positioner<Item> for IndexPositioner
where
    Item: PartialEq + Clone,
{
    type Position = usize;

    #[inline]
    fn position(&self) -> usize {
        self.0
    }

    #[inline]
    fn update(&mut self, _item: &Item) {
        self.0 += 1
    }
}

impl IndexPositioner {
    pub fn new() -> IndexPositioner {
        IndexPositioner::new_with_position(0)
    }

    pub fn new_with_position(position: usize) -> IndexPositioner {
        IndexPositioner(position)
    }
}

impl<Item, Range> RangePositioner<Item, Range> for IndexPositioner
where
    Item: PartialEq + Clone,
    Range: PartialEq + Clone + crate::stream::Range,
{
    fn update_range(&mut self, range: &Range) {
        self.0 += range.len()
    }
}

/// Struct which represents a position in a source file.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct SourcePosition {
    /// Current line of the input
    pub line: i32,
    /// Current column of the input
    pub column: i32,
}

impl Default for SourcePosition {
    fn default() -> Self {
        SourcePosition { line: 1, column: 1 }
    }
}

impl fmt::Display for SourcePosition {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "line: {}, column: {}", self.line, self.column)
    }
}

impl SourcePosition {
    pub fn new() -> Self {
        SourcePosition::default()
    }
}

impl Positioner<char> for SourcePosition {
    type Position = SourcePosition;

    #[inline]
    fn position(&self) -> SourcePosition {
        self.clone()
    }

    #[inline]
    fn update(&mut self, token: &char) {
        self.column += 1;
        if *token == '\n' {
            self.column = 1;
            self.line += 1;
        }
    }
}

impl Positioner<u8> for SourcePosition {
    type Position = SourcePosition;

    #[inline]
    fn position(&self) -> SourcePosition {
        self.clone()
    }

    #[inline]
    fn update(&mut self, token: &u8) {
        self.column += 1;
        if *token == b'\n' {
            self.column = 1;
            self.line += 1;
        }
    }
}

impl<'a> RangePositioner<char, &'a str> for SourcePosition {
    fn update_range(&mut self, range: &&'a str) {
        for c in range.chars() {
            self.update(&c);
        }
    }
}

impl<Input, X, S> RangeStreamOnce for Stream<Input, X>
where
    Input: RangeStreamOnce,
    X: Clone + RangePositioner<Input::Token, Input::Range>,
    S: StreamError<Input::Token, Input::Range>,
    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
    Input::Position: Clone + Ord,
{
    #[inline]
    fn uncons_range(&mut self, size: usize) -> Result<Input::Range, StreamErrorFor<Self>> {
        self.input.uncons_range(size).map(|range| {
            self.positioner.update_range(&range);
            range
        })
    }

    #[inline]
    fn uncons_while<F>(&mut self, mut predicate: F) -> Result<Input::Range, StreamErrorFor<Self>>
    where
        F: FnMut(Input::Token) -> bool,
    {
        let positioner = &mut self.positioner;
        self.input.uncons_while(|t| {
            if predicate(t.clone()) {
                positioner.update(&t);
                true
            } else {
                false
            }
        })
    }

    #[inline]
    fn uncons_while1<F>(
        &mut self,
        mut predicate: F,
    ) -> ParseResult<Self::Range, StreamErrorFor<Self>>
    where
        F: FnMut(Self::Token) -> bool,
    {
        let positioner = &mut self.positioner;
        self.input.uncons_while1(|t| {
            if predicate(t.clone()) {
                positioner.update(&t);
                true
            } else {
                false
            }
        })
    }

    #[inline]
    fn distance(&self, end: &Self::Checkpoint) -> usize {
        self.input.distance(&end.input)
    }

    fn range(&self) -> Self::Range {
        self.input.range()
    }
}

impl<Input, X, S> ResetStream for Stream<Input, X>
where
    Input: ResetStream,
    X: Clone + Positioner<Input::Token>,
    S: StreamError<Input::Token, Input::Range>,
    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
{
    type Checkpoint = Stream<Input::Checkpoint, X>;
    fn checkpoint(&self) -> Self::Checkpoint {
        Stream {
            input: self.input.checkpoint(),
            positioner: self.positioner.clone(),
        }
    }
    fn reset(&mut self, checkpoint: Self::Checkpoint) -> Result<(), Self::Error> {
        self.input.reset(checkpoint.input)?;
        self.positioner = checkpoint.positioner;
        Ok(())
    }
}

#[cfg(all(feature = "std", test))]
mod tests {

    use crate::Parser;

    use super::*;

    #[test]
    fn test_positioner() {
        let input = ["a".to_string(), "b".to_string()];
        let mut parser = crate::any();
        let result = parser.parse(Stream::new(&input[..]));
        assert_eq!(
            result,
            Ok((
                "a".to_string(),
                Stream::with_positioner(
                    &["b".to_string()][..],
                    IndexPositioner::new_with_position(1)
                )
            ))
        );
    }

    #[test]
    fn test_range_positioner() {
        let input = ["a".to_string(), "b".to_string(), "c".to_string()];
        let mut parser = crate::parser::range::take(2);
        let result = parser.parse(Stream::new(&input[..]));
        assert_eq!(
            result,
            Ok((
                &["a".to_string(), "b".to_string()][..],
                Stream::with_positioner(
                    &["c".to_string()][..],
                    IndexPositioner::new_with_position(2)
                )
            ))
        );
    }
}
<|endoftext|>


<commit_before>use crate::constants::*;

#[derive(Clone, Debug, PartialEq)]
pub enum Style {
    Old,
    OldInverse,
    New,
    NewInverse,
    Error,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StyledToken {
    token: String,
    style: Style,
}

impl StyledToken {
    pub fn new(token: String, style: Style) -> StyledToken {
        return StyledToken { token, style };
    }

    pub fn is_whitespace(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        if chars_iterator.next().is_some() {
            // Multiple chars found in this token, but whitespace will only be
            // one per token.
            return false;
        }

        return first_char.is_whitespace();
    }
}

pub struct TokenCollector {
    line_prefix: StyledToken,
    tokens: Vec<StyledToken>,
    bytes_count: usize,
    highlighted_bytes_count: usize,
    rendered: bool,
}

impl Style {
    #[must_use]
    pub fn is_inverse(&self) -> bool {
        match self {
            Style::OldInverse | Style::NewInverse | Style::Error => {
                return true;
            }
            _ => {
                return false;
            }
        }
    }

    #[must_use]
    pub fn color<'a>(&self) -> &'a str {
        match self {
            Style::Old => {
                return OLD;
            }
            Style::OldInverse => {
                return OLD;
            }
            Style::New => {
                return NEW;
            }
            Style::NewInverse => {
                return NEW;
            }
            Style::Error => {
                return ERROR;
            }
        }
    }
}

impl TokenCollector {
    #[must_use]
    pub fn create(line_prefix: StyledToken) -> Self {
        return TokenCollector {
            line_prefix,
            tokens: Vec::new(),
            bytes_count: 0,
            highlighted_bytes_count: 0,
            rendered: false,
        };
    }

    pub fn push(&mut self, token: StyledToken) {
        self.tokens.push(token);
    }

    #[must_use]
    fn render_row(&self, row: &mut [StyledToken]) -> String {
        let mut rendered = String::new();

        if row.is_empty() {
            return rendered;
        }

        if self.line_prefix.style == Style::New {
            highlight_trailing_whitespace(row);
            highlight_nonleading_tab(row);
        }

        // Set inverse from prefix
        let mut is_inverse = self.line_prefix.style.is_inverse();
        if is_inverse {
            rendered.push_str(INVERSE_VIDEO);
        }

        // Set line color from prefix
        let mut color = self.line_prefix.style.color();
        rendered.push_str(self.line_prefix.style.color());

        // Render prefix
        rendered.push_str(&self.line_prefix.token);

        for token in row {
            if token.style.is_inverse() && !is_inverse {
                rendered.push_str(INVERSE_VIDEO);
            }
            if is_inverse && !token.style.is_inverse() {
                rendered.push_str(NOT_INVERSE_VIDEO);
            }
            is_inverse = token.style.is_inverse();

            if token.style.color() != color {
                rendered.push_str(token.style.color());
                color = token.style.color();
            }

            rendered.push_str(&token.token);
        }

        rendered.push_str(NORMAL);

        return rendered;
    }

    #[must_use]
    pub fn render(&mut self) -> String {
        assert!(!self.rendered);
        let mut current_row: Vec<StyledToken> = Vec::new();
        let mut rendered = String::new();

        for token in &self.tokens {
            self.bytes_count += token.token.len();
            if token.style.is_inverse() {
                self.highlighted_bytes_count += token.token.len();
            }

            if token.token == "\n" {
                let rendered_row = &self.render_row(&mut current_row);
                rendered.push_str(rendered_row);
                rendered.push('\n');
                current_row.clear();
                continue;
            }

            current_row.push(token.clone());
        }

        if !current_row.is_empty() {
            let rendered_row = &self.render_row(&mut current_row);
            rendered.push_str(rendered_row);
        }

        self.rendered = true;
        return rendered;
    }

    pub fn chars_count(&self) -> usize {
        assert!(self.rendered); // It's the rendering that does the counting
        return self.bytes_count;
    }

    pub fn highlighted_chars_count(&self) -> usize {
        assert!(self.rendered); // It's the rendering that does the counting
        return self.highlighted_bytes_count;
    }
}

fn highlight_trailing_whitespace(row: &mut [StyledToken]) {
    for token in row.iter_mut().rev() {
        if !token.is_whitespace() {
            return;
        }

        token.style = Style::Error;
    }
}

fn highlight_nonleading_tab(row: &mut [StyledToken]) {
    let mut token_iter = row.iter_mut();

    // Skip leading TABs
    loop {
        let next = token_iter.next();
        if next.is_none() {
            // Done!
            return;
        }

        let token = next.unwrap();
        if token.token != "\t" {
            // Not a TAB, this means we're out of skipping the leading TABs
            break;
        }
    }

    // Scan the rest of the line for non-leading TABs
    for token in token_iter {
        if token.token != "\t" {
            // Not a TAB, never mind
            continue;
        }

        // Non-leading TAB, mark it!
        token.style = Style::Error;
    }
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_basic() {
        let mut test_me = TokenCollector::create(StyledToken {
            token: "+".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "hej".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "\n".to_string(),
            style: Style::New,
        });

        let rendered = test_me.render();
        assert_eq!(rendered, format!("{}+hej{}\n", NEW, NORMAL));
    }

    #[test]
    fn test_add_trailing_whitespace() {
        // Just a whitespace
        let mut row = [StyledToken::new(" ".to_string(), Style::New)];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(row, [StyledToken::new(" ".to_string(), Style::Error)]);

        // Trailing whitespace
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new(" ".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new(" ".to_string(), Style::Error),
            ]
        );

        // Leading whitespace
        let mut row = [
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new(" ".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );
    }

    #[test]
    fn test_removed_trailing_whitespace() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new(" ".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}- {}", OLD, NORMAL));
    }

    #[test]
    fn test_add_nonleading_tab() {
        // Trailing TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
            ]
        );

        // Middle TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("y".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
                StyledToken::new("y".to_string(), Style::New),
            ]
        );

        // Leading TAB (don't highlight)
        let mut row = [
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("\t".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );

        // Single TAB (don't highlight because it is leading)
        let mut row = [StyledToken::new("\t".to_string(), Style::New)];
        highlight_nonleading_tab(&mut row);
        assert_eq!(row, [StyledToken::new("\t".to_string(), Style::New),]);
    }

    #[test]
    fn test_removed_nonleading_tab() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new("x".to_string(), Style::Old));
        test_me.push(StyledToken::new("\t".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}-x\t{}", OLD, NORMAL));
    }
}
<commit_msg>5% performance improvement<commit_after>use crate::constants::*;

#[derive(Clone, Debug, PartialEq)]
pub enum Style {
    Old,
    OldInverse,
    New,
    NewInverse,
    Error,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StyledToken {
    token: String,
    style: Style,
}

impl StyledToken {
    pub fn new(token: String, style: Style) -> StyledToken {
        return StyledToken { token, style };
    }

    pub fn is_whitespace(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        if chars_iterator.next().is_some() {
            // Multiple chars found in this token, but whitespace will only be
            // one per token.
            return false;
        }

        return first_char.is_whitespace();
    }
}

pub struct TokenCollector {
    line_prefix: StyledToken,
    tokens: Vec<StyledToken>,
    bytes_count: usize,
    highlighted_bytes_count: usize,
    rendered: bool,
}

impl Style {
    #[must_use]
    pub fn is_inverse(&self) -> bool {
        match self {
            Style::OldInverse | Style::NewInverse | Style::Error => {
                return true;
            }
            _ => {
                return false;
            }
        }
    }

    #[must_use]
    pub fn color<'a>(&self) -> &'a str {
        match self {
            Style::Old => {
                return OLD;
            }
            Style::OldInverse => {
                return OLD;
            }
            Style::New => {
                return NEW;
            }
            Style::NewInverse => {
                return NEW;
            }
            Style::Error => {
                return ERROR;
            }
        }
    }
}

impl TokenCollector {
    #[must_use]
    pub fn create(line_prefix: StyledToken) -> Self {
        return TokenCollector {
            line_prefix,
            tokens: Vec::new(),
            bytes_count: 0,
            highlighted_bytes_count: 0,
            rendered: false,
        };
    }

    pub fn push(&mut self, token: StyledToken) {
        self.tokens.push(token);
    }

    #[must_use]
    fn render_row(&self, row: &mut [StyledToken]) -> String {
        let mut rendered = String::new();

        if row.is_empty() {
            return rendered;
        }

        if self.line_prefix.style == Style::New {
            highlight_trailing_whitespace(row);
            highlight_nonleading_tab(row);
        }

        // Set inverse from prefix
        let mut is_inverse = self.line_prefix.style.is_inverse();
        if is_inverse {
            rendered.push_str(INVERSE_VIDEO);
        }

        // Set line color from prefix
        let mut color = self.line_prefix.style.color();
        rendered.push_str(self.line_prefix.style.color());

        // Render prefix
        rendered.push_str(&self.line_prefix.token);

        for token in row {
            if token.style.is_inverse() && !is_inverse {
                rendered.push_str(INVERSE_VIDEO);
            }
            if is_inverse && !token.style.is_inverse() {
                rendered.push_str(NOT_INVERSE_VIDEO);
            }
            is_inverse = token.style.is_inverse();

            if token.style.color() != color {
                rendered.push_str(token.style.color());
                color = token.style.color();
            }

            rendered.push_str(&token.token);
        }

        rendered.push_str(NORMAL);

        return rendered;
    }

    #[must_use]
    pub fn render(&mut self) -> String {
        assert!(!self.rendered);
        let mut current_row: Vec<StyledToken> = Vec::new();
        let mut rendered = String::new();

        let tokens = std::mem::take(&mut self.tokens);
        for token in tokens {
            self.bytes_count += token.token.len();
            if token.style.is_inverse() {
                self.highlighted_bytes_count += token.token.len();
            }

            if token.token == "\n" {
                let rendered_row = &self.render_row(&mut current_row);
                rendered.push_str(rendered_row);
                rendered.push('\n');
                current_row.clear();
                continue;
            }

            current_row.push(token);
        }

        if !current_row.is_empty() {
            let rendered_row = &self.render_row(&mut current_row);
            rendered.push_str(rendered_row);
        }

        self.rendered = true;
        return rendered;
    }

    pub fn chars_count(&self) -> usize {
        assert!(self.rendered); // It's the rendering that does the counting
        return self.bytes_count;
    }

    pub fn highlighted_chars_count(&self) -> usize {
        assert!(self.rendered); // It's the rendering that does the counting
        return self.highlighted_bytes_count;
    }
}

fn highlight_trailing_whitespace(row: &mut [StyledToken]) {
    for token in row.iter_mut().rev() {
        if !token.is_whitespace() {
            return;
        }

        token.style = Style::Error;
    }
}

fn highlight_nonleading_tab(row: &mut [StyledToken]) {
    let mut token_iter = row.iter_mut();

    // Skip leading TABs
    loop {
        let next = token_iter.next();
        if next.is_none() {
            // Done!
            return;
        }

        let token = next.unwrap();
        if token.token != "\t" {
            // Not a TAB, this means we're out of skipping the leading TABs
            break;
        }
    }

    // Scan the rest of the line for non-leading TABs
    for token in token_iter {
        if token.token != "\t" {
            // Not a TAB, never mind
            continue;
        }

        // Non-leading TAB, mark it!
        token.style = Style::Error;
    }
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_basic() {
        let mut test_me = TokenCollector::create(StyledToken {
            token: "+".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "hej".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "\n".to_string(),
            style: Style::New,
        });

        let rendered = test_me.render();
        assert_eq!(rendered, format!("{}+hej{}\n", NEW, NORMAL));
    }

    #[test]
    fn test_add_trailing_whitespace() {
        // Just a whitespace
        let mut row = [StyledToken::new(" ".to_string(), Style::New)];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(row, [StyledToken::new(" ".to_string(), Style::Error)]);

        // Trailing whitespace
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new(" ".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new(" ".to_string(), Style::Error),
            ]
        );

        // Leading whitespace
        let mut row = [
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new(" ".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );
    }

    #[test]
    fn test_removed_trailing_whitespace() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new(" ".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}- {}", OLD, NORMAL));
    }

    #[test]
    fn test_add_nonleading_tab() {
        // Trailing TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
            ]
        );

        // Middle TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("y".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
                StyledToken::new("y".to_string(), Style::New),
            ]
        );

        // Leading TAB (don't highlight)
        let mut row = [
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("\t".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );

        // Single TAB (don't highlight because it is leading)
        let mut row = [StyledToken::new("\t".to_string(), Style::New)];
        highlight_nonleading_tab(&mut row);
        assert_eq!(row, [StyledToken::new("\t".to_string(), Style::New),]);
    }

    #[test]
    fn test_removed_nonleading_tab() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new("x".to_string(), Style::Old));
        test_me.push(StyledToken::new("\t".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}-x\t{}", OLD, NORMAL));
    }
}
<|endoftext|>


<commit_before>use super::Opcode;
use vm::{Machine, Memory, Stack, PC, Gas};

const G_ZERO: isize = 0;
const G_BASE: isize = 2;
const G_VERYLOW: isize = 3;
const G_LOW: isize = 5;
const G_MID: isize = 8;
const G_HIGH: isize = 10;
const G_EXTCODE: isize = 700;
const G_BALANCE: isize = 400;
const G_SLOAD: isize = 200;
const G_JUMPDEST: isize = 1;
const G_SSET: isize = 20000;
const G_SRESET: isize = 5000;
const R_SCLEAR: isize = 15000;
const R_SELFDESTRUCT: isize = 24000;
const G_SELFDESTRUCT: isize = 5000;
const G_CREATE: isize = 32000;
const G_CODEDEPOSITE: isize = 200;
const G_CALL: isize = 700;
const G_CALLVALUE: isize = 9000;
const G_CALLSTIPEND: isize = 2300;
const G_NEWACCOUNT: isize = 25000;
const G_EXP: isize = 10;
const G_EXPBYTE: isize = 10;
const G_MEMORY: isize = 3;
const G_TXCREATE: isize = 32000;
const G_TXDATAZERO: isize = 4;
const G_TXDATANONZERO: isize = 68;
const G_TRANSACTION: isize = 21000;
const G_LOG: isize = 375;
const G_LOGDATA: isize = 8;
const G_LOGTOPIC: isize = 375;
const G_SHA3: isize = 30;
const G_SHA3WORD: isize = 6;
const G_COPY: isize = 3;
const G_BLOCKHASH: isize = 20;

fn memory_cost(a: usize) -> Gas {
    let a = a as isize;
    (G_MEMORY * a + a * a / 512).into()
}

// TODO: Implement C_SSTORE, C_CALL and C_SELFDESTRUCT
// TODO: Use a machine_state struct instead of u_ip, u_i and u_s
// TODO: Use machine_state to implement gas cost for EXP,
// CALLDATACOPY, CODECOPY, EXTCODECOPY, LOG0-4, SHA3

impl Opcode {
    pub fn gas_cost_before<M: Memory, S: Stack>(&self, machine: &Machine<M, S>) -> Gas {
        let opcode = self.clone();
        let self_cost: Gas = match opcode {
            // Unimplemented
            Opcode::SSTORE | Opcode::EXP | Opcode::CALLDATACOPY |
            Opcode::CODECOPY | Opcode::EXTCODECOPY | Opcode::LOG(_) |
            Opcode::CALL | Opcode::CALLCODE | Opcode::DELEGATECALL |
            Opcode::SELFDESTRUCT | Opcode::SHA3 | Opcode::EXTCODESIZE
                => unimplemented!(),

            Opcode::CREATE => G_CREATE.into(),
            Opcode::JUMPDEST => G_JUMPDEST.into(),
            Opcode::SLOAD => G_SLOAD.into(),

            // W_zero
            Opcode::STOP | Opcode::RETURN
                => G_ZERO.into(),

            // W_base
            Opcode::ADDRESS | Opcode::ORIGIN | Opcode::CALLER |
            Opcode::CALLVALUE | Opcode::CALLDATASIZE |
            Opcode::CODESIZE | Opcode::GASPRICE | Opcode::COINBASE |
            Opcode::TIMESTAMP | Opcode::NUMBER | Opcode::DIFFICULTY |
            Opcode::GASLIMIT | Opcode::POP | Opcode::PC |
            Opcode::MSIZE | Opcode::GAS
                => G_BASE.into(),

            // W_verylow
            Opcode::ADD | Opcode::SUB | Opcode::NOT | Opcode::LT |
            Opcode::GT | Opcode::SLT | Opcode::SGT | Opcode::EQ |
            Opcode::ISZERO | Opcode::AND | Opcode::OR | Opcode::XOR |
            Opcode::BYTE | Opcode::CALLDATALOAD | Opcode::MLOAD |
            Opcode::MSTORE | Opcode::MSTORE8 | Opcode::PUSH(_) |
            Opcode::DUP(_) | Opcode::SWAP(_)
                => G_VERYLOW.into(),

            // W_low
            Opcode::MUL | Opcode::DIV | Opcode::SDIV | Opcode::MOD |
            Opcode::SMOD | Opcode::SIGNEXTEND
                => G_LOW.into(),

            // W_mid
            Opcode::ADDMOD | Opcode::MULMOD | Opcode::JUMP
                => G_MID.into(),

            // W_high
            Opcode::JUMPI => G_HIGH.into(),

            Opcode::BALANCE => G_BALANCE.into(),
            Opcode::BLOCKHASH => G_BLOCKHASH.into(),
            Opcode::INVALID => Gas::zero(),
        };
        self_cost - memory_cost(machine.memory.active_len())
    }

    pub fn gas_cost_after<M: Memory, S: Stack>(&self, machine: &Machine<M, S>) -> Gas {
        memory_cost(machine.memory.active_len())
    }
}
<commit_msg>Problem: no gas cost calculation for EXP Solution: implement it!<commit_after>use utils::u256::U256;
use super::Opcode;
use vm::{Machine, Memory, Stack, PC, Gas};

const G_ZERO: isize = 0;
const G_BASE: isize = 2;
const G_VERYLOW: isize = 3;
const G_LOW: isize = 5;
const G_MID: isize = 8;
const G_HIGH: isize = 10;
const G_EXTCODE: isize = 700;
const G_BALANCE: isize = 400;
const G_SLOAD: isize = 200;
const G_JUMPDEST: isize = 1;
const G_SSET: isize = 20000;
const G_SRESET: isize = 5000;
const R_SCLEAR: isize = 15000;
const R_SELFDESTRUCT: isize = 24000;
const G_SELFDESTRUCT: isize = 5000;
const G_CREATE: isize = 32000;
const G_CODEDEPOSITE: isize = 200;
const G_CALL: isize = 700;
const G_CALLVALUE: isize = 9000;
const G_CALLSTIPEND: isize = 2300;
const G_NEWACCOUNT: isize = 25000;
const G_EXP: isize = 10;
const G_EXPBYTE: isize = 10;
const G_MEMORY: isize = 3;
const G_TXCREATE: isize = 32000;
const G_TXDATAZERO: isize = 4;
const G_TXDATANONZERO: isize = 68;
const G_TRANSACTION: isize = 21000;
const G_LOG: isize = 375;
const G_LOGDATA: isize = 8;
const G_LOGTOPIC: isize = 375;
const G_SHA3: isize = 30;
const G_SHA3WORD: isize = 6;
const G_COPY: isize = 3;
const G_BLOCKHASH: isize = 20;

fn memory_cost(a: usize) -> Gas {
    let a = a as isize;
    (G_MEMORY * a + a * a / 512).into()
}

// TODO: Implement C_SSTORE, C_CALL and C_SELFDESTRUCT
// TODO: Use a machine_state struct instead of u_ip, u_i and u_s
// TODO: Use machine_state to implement gas cost for EXP,
// CALLDATACOPY, CODECOPY, EXTCODECOPY, LOG0-4, SHA3

impl Opcode {
    pub fn gas_cost_before<M: Memory, S: Stack>(&self, machine: &Machine<M, S>) -> Gas {
        let ref stack = machine.stack;
        let ref memory = machine.memory;
        let opcode = self.clone();
        let self_cost: Gas = match opcode {
            // Unimplemented
            Opcode::SSTORE | Opcode::EXP | Opcode::CALLDATACOPY |
            Opcode::CODECOPY | Opcode::EXTCODECOPY | Opcode::LOG(_) |
            Opcode::CALL | Opcode::CALLCODE | Opcode::DELEGATECALL |
            Opcode::SELFDESTRUCT | Opcode::SHA3 | Opcode::EXTCODESIZE
                => unimplemented!(),

            Opcode::EXP => {
                if *stack.peek(1) == U256::zero() {
                    G_EXP.into()
                } else {
                    (G_EXP + G_EXPBYTE * (1 + stack.peek(1).log2floor())).into()
                }
            }

            Opcode::CREATE => G_CREATE.into(),
            Opcode::JUMPDEST => G_JUMPDEST.into(),
            Opcode::SLOAD => G_SLOAD.into(),

            // W_zero
            Opcode::STOP | Opcode::RETURN
                => G_ZERO.into(),

            // W_base
            Opcode::ADDRESS | Opcode::ORIGIN | Opcode::CALLER |
            Opcode::CALLVALUE | Opcode::CALLDATASIZE |
            Opcode::CODESIZE | Opcode::GASPRICE | Opcode::COINBASE |
            Opcode::TIMESTAMP | Opcode::NUMBER | Opcode::DIFFICULTY |
            Opcode::GASLIMIT | Opcode::POP | Opcode::PC |
            Opcode::MSIZE | Opcode::GAS
                => G_BASE.into(),

            // W_verylow
            Opcode::ADD | Opcode::SUB | Opcode::NOT | Opcode::LT |
            Opcode::GT | Opcode::SLT | Opcode::SGT | Opcode::EQ |
            Opcode::ISZERO | Opcode::AND | Opcode::OR | Opcode::XOR |
            Opcode::BYTE | Opcode::CALLDATALOAD | Opcode::MLOAD |
            Opcode::MSTORE | Opcode::MSTORE8 | Opcode::PUSH(_) |
            Opcode::DUP(_) | Opcode::SWAP(_)
                => G_VERYLOW.into(),

            // W_low
            Opcode::MUL | Opcode::DIV | Opcode::SDIV | Opcode::MOD |
            Opcode::SMOD | Opcode::SIGNEXTEND
                => G_LOW.into(),

            // W_mid
            Opcode::ADDMOD | Opcode::MULMOD | Opcode::JUMP
                => G_MID.into(),

            // W_high
            Opcode::JUMPI => G_HIGH.into(),

            Opcode::BALANCE => G_BALANCE.into(),
            Opcode::BLOCKHASH => G_BLOCKHASH.into(),
            Opcode::INVALID => Gas::zero(),
        };
        self_cost - memory_cost(machine.memory.active_len())
    }

    pub fn gas_cost_after<M: Memory, S: Stack>(&self, machine: &Machine<M, S>) -> Gas {
        memory_cost(machine.memory.active_len())
    }
}
<|endoftext|>


<commit_before>extern crate chrono;

use self::chrono::{DateTime, Utc};
use std::env;
use std::time::{SystemTime, UNIX_EPOCH};

pub fn read_env_var(var: &str) -> String {
    env::var_os(var)
        .expect(&format!(
            "{} must be specified. \
             Did you forget to add it to your .env file?",
            var
        ))
        .into_string()
        .expect(&format!("{} does not contain a valid UTF8 string", var))
}

pub fn elapsed_ms(from: DateTime<Utc>, to: DateTime<Utc>) -> Result<u64, ()> {
    let ms = to.signed_duration_since(from).num_milliseconds();
    if ms >= 0 { Ok(ms as u64) } else { Err(()) }
}

pub fn timestamp() -> u64 {
    let now = SystemTime::now();
    let elapsed = now.duration_since(UNIX_EPOCH).expect("Time went backwards");
    let in_ms = elapsed.as_secs() * 1000 + elapsed.subsec_nanos() as u64 / 1_000_000;
    in_ms
}

pub fn clamp<T>(val: T, min: T, max: T) -> T
where
    T: Ord,
{
    match (val < min, val > max) {
        (true, _) => min,
        (_, true) => max,
        _ => val,
    }
}

pub type SeqId = u32;
pub struct SeqIdGen {
    curr_id: SeqId,
}
impl SeqIdGen {
    pub fn new() -> Self {
        SeqIdGen { curr_id: 0 }
    }

    pub fn gen(&mut self) -> SeqId {
        let curr_id = self.curr_id;
        self.curr_id += 1;
        curr_id
    }
}

#[macro_export]
macro_rules! newtype {
    (  $name:ident($type:ty)  ) => {
        pub struct $name(pub $type);
        add_impl!($name, $type);
    };
    (  $name:ident($type:ty) : $($derives:meta), + ) => {
        #[derive(
            $($derives,)+
        )]
        pub struct $name(pub $type);
        add_impl!($name, $type);
    };
}

macro_rules! add_impl {
     (  $name:ident, $type:ty ) => {
         impl Deref for $name {
            type Target = $type;

            fn deref(&self) -> &$type {
                &self.0
            }
        }
        impl DerefMut for $name {
            fn deref_mut(&mut self) -> &mut $type {
                &mut self.0
            }
        }
        impl From<$type> for $name {
            fn from(t: $type) -> Self {
                $name(t)
            }
        }
     };
}

#[cfg(test)]
use util::chrono::TimeZone;

#[test]
fn read_string_envvar() {
    env::set_var("TEST", "foo");
    assert_eq!("foo", &read_env_var("TEST"));
}

#[test]
#[should_panic]
fn read_empty_envvar() {
    env::remove_var("EMPTY");
    read_env_var("EMPTY");
}

#[test]
fn one_elapsed_ms() {
    let a = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 0);
    let b = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 1);
    assert_eq!(1, elapsed_ms(a, b).unwrap());
}

#[test]
fn one_elapsed_second() {
    let a = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 0);
    let b = Utc.ymd(1970, 1, 1).and_hms(0, 0, 1);
    assert_eq!(1000, elapsed_ms(a, b).unwrap());
}

#[test]
fn no_elapsed_time() {
    let a = Utc.ymd(1970, 1, 1).and_hms(0, 0, 1);
    assert_eq!(0, elapsed_ms(a, a).unwrap());
}

#[test]
fn negative_elapsed_time() {
    let a = Utc.ymd(1970, 1, 1).and_hms(0, 0, 1);
    let b = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0);
    assert!(elapsed_ms(a, b).is_err());
}

#[test]
fn timestamp_wait() {
    use std::thread;
    use std::time::Duration;

    let a = timestamp();
    let delta = 420;
    thread::sleep(Duration::from_millis(delta));
    let b = timestamp();
    assert!(b - a >= delta)
}

#[test]
fn clamp_in_range() {
    let res = clamp(1, 0, 2);
    assert_eq!(1, res);
}

#[test]
fn clamp_min() {
    let res = clamp(-2, -2, 2);
    assert_eq!(-2, res);
}

#[test]
fn clamp_max() {
    let res = clamp(0, -2, 0);
    assert_eq!(0, res);
}

#[test]
fn clamp_less_than_min() {
    let res = clamp(-1, 0, 2);
    assert_eq!(0, res);
}

#[test]
fn clamp_more_than_max() {
    let res = clamp(999, 9, 10);
    assert_eq!(10, res);
}

#[test]
fn seq_id_gen_sequential() {
    let mut id_gen = SeqIdGen::new();
    let ids_count = 1000;
    for i in 0..ids_count {
        assert_eq!(i, id_gen.gen());
    }
}
<commit_msg>Core: Optimize SeqIdGen to never generate falsy values<commit_after>extern crate chrono;

use self::chrono::{DateTime, Utc};
use std::env;
use std::time::{SystemTime, UNIX_EPOCH};

pub fn read_env_var(var: &str) -> String {
    env::var_os(var)
        .expect(&format!(
            "{} must be specified. \
             Did you forget to add it to your .env file?",
            var
        ))
        .into_string()
        .expect(&format!("{} does not contain a valid UTF8 string", var))
}

pub fn elapsed_ms(from: DateTime<Utc>, to: DateTime<Utc>) -> Result<u64, ()> {
    let ms = to.signed_duration_since(from).num_milliseconds();
    if ms >= 0 { Ok(ms as u64) } else { Err(()) }
}

pub fn timestamp() -> u64 {
    let now = SystemTime::now();
    let elapsed = now.duration_since(UNIX_EPOCH).expect("Time went backwards");
    let in_ms = elapsed.as_secs() * 1000 + elapsed.subsec_nanos() as u64 / 1_000_000;
    in_ms
}

pub fn clamp<T>(val: T, min: T, max: T) -> T
where
    T: Ord,
{
    match (val < min, val > max) {
        (true, _) => min,
        (_, true) => max,
        _ => val,
    }
}

pub type SeqId = u32;
pub struct SeqIdGen {
    curr_id: SeqId,
}
impl SeqIdGen {
    pub fn new() -> Self {
        SeqIdGen { curr_id: 0 }
    }

    pub fn gen(&mut self) -> SeqId {
        self.curr_id += 1;
        self.curr_id
    }
}

#[macro_export]
macro_rules! newtype {
    (  $name:ident($type:ty)  ) => {
        pub struct $name(pub $type);
        add_impl!($name, $type);
    };
    (  $name:ident($type:ty) : $($derives:meta), + ) => {
        #[derive(
            $($derives,)+
        )]
        pub struct $name(pub $type);
        add_impl!($name, $type);
    };
}

macro_rules! add_impl {
     (  $name:ident, $type:ty ) => {
         impl Deref for $name {
            type Target = $type;

            fn deref(&self) -> &$type {
                &self.0
            }
        }
        impl DerefMut for $name {
            fn deref_mut(&mut self) -> &mut $type {
                &mut self.0
            }
        }
        impl From<$type> for $name {
            fn from(t: $type) -> Self {
                $name(t)
            }
        }
     };
}

#[cfg(test)]
use util::chrono::TimeZone;

#[test]
fn read_string_envvar() {
    env::set_var("TEST", "foo");
    assert_eq!("foo", &read_env_var("TEST"));
}

#[test]
#[should_panic]
fn read_empty_envvar() {
    env::remove_var("EMPTY");
    read_env_var("EMPTY");
}

#[test]
fn one_elapsed_ms() {
    let a = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 0);
    let b = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 1);
    assert_eq!(1, elapsed_ms(a, b).unwrap());
}

#[test]
fn one_elapsed_second() {
    let a = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 0);
    let b = Utc.ymd(1970, 1, 1).and_hms(0, 0, 1);
    assert_eq!(1000, elapsed_ms(a, b).unwrap());
}

#[test]
fn no_elapsed_time() {
    let a = Utc.ymd(1970, 1, 1).and_hms(0, 0, 1);
    assert_eq!(0, elapsed_ms(a, a).unwrap());
}

#[test]
fn negative_elapsed_time() {
    let a = Utc.ymd(1970, 1, 1).and_hms(0, 0, 1);
    let b = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0);
    assert!(elapsed_ms(a, b).is_err());
}

#[test]
fn timestamp_wait() {
    use std::thread;
    use std::time::Duration;

    let a = timestamp();
    let delta = 420;
    thread::sleep(Duration::from_millis(delta));
    let b = timestamp();
    assert!(b - a >= delta)
}

#[test]
fn clamp_in_range() {
    let res = clamp(1, 0, 2);
    assert_eq!(1, res);
}

#[test]
fn clamp_min() {
    let res = clamp(-2, -2, 2);
    assert_eq!(-2, res);
}

#[test]
fn clamp_max() {
    let res = clamp(0, -2, 0);
    assert_eq!(0, res);
}

#[test]
fn clamp_less_than_min() {
    let res = clamp(-1, 0, 2);
    assert_eq!(0, res);
}

#[test]
fn clamp_more_than_max() {
    let res = clamp(999, 9, 10);
    assert_eq!(10, res);
}

#[test]
fn seq_id_gen_sequential() {
    let mut id_gen = SeqIdGen::new();
    let ids_count = 1000;
    for i in 0..ids_count {
        assert_eq!(i + 1, id_gen.gen());
    }
}
<|endoftext|>


<commit_before>fn main() {
	println!("Hello, world!")
}
<commit_msg>Add some stuff.<commit_after>struct Processor {
	accumulator:     u8,
	index_x:         u8,
	index_y:         u8,
	stack_pointer:   u8,
	program_counter: u16,
	status:          u8,
}

impl Processor {
}

#[deriving(PartialEq)]
#[deriving(Eq)]
#[deriving(PartialOrd)]
#[deriving(Ord)]
struct Address(u16);

impl Address {
	fn to_int(&self) -> u16 {
		match *self {
			Address(address_) => address_
		}
	}

	fn min() -> Address { Address(0x0100) }
	fn max() -> Address { Address(0x01ff) }

	fn is_valid(&self) -> bool {
		Address::min() <= *self && *self <= Address::max()
	}
}

struct Memory {
	bytes: [u8,.. 256]
}

impl Memory {
	fn address_to_byte_offset(address: &Address) -> uint {
		(address.to_int() - Address::min().to_int()) as uint
	}

	fn get_byte(&self, address: &Address) -> u8 {
		if !address.is_valid()
		{
			fail!("Invalid address.");
		}
		else
		{
			return self.bytes[Memory::address_to_byte_offset(address)];
		}
	}

	// Sets the byte at the given address to the given value and returns the
	// previous value at the address.
	fn set_byte(&mut self, address: &Address, value: u8) -> u8 {
		if !address.is_valid()
		{
			fail!("Invalid address.");
		}
		else
		{
			let old_value = self.get_byte(address);
			self.bytes[Memory::address_to_byte_offset(address)] = value;

			return old_value;
		}
	}
}

fn main() {
	println!("Hello, world!")
}
<|endoftext|>


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

//! CSS handling for the computed value of
//! [grids](https://drafts.csswg.org/css-grid/)

use cssparser::{Parser, Token, ParseError as CssParseError};
use parser::{Parse, ParserContext};
#[allow(unused_imports)] use std::ascii::AsciiExt;
use std::mem;
use style_traits::{ParseError, StyleParseErrorKind};
use values::{CSSFloat, CustomIdent};
use values::computed::{self, Context, ToComputedValue};
use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat};
use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType, TrackListValue};
use values::specified::{LengthOrPercentage, Integer};

/// Parse a single flexible length.
pub fn parse_flex<'i, 't>(input: &mut Parser<'i, 't>) -> Result<CSSFloat, ParseError<'i>> {
    let location = input.current_source_location();
    match *input.next()? {
        Token::Dimension { value, ref unit, .. } if unit.eq_ignore_ascii_case("fr") && value.is_sign_positive()
            => Ok(value),
        ref t => Err(location.new_unexpected_token_error(t.clone())),
    }
}

impl Parse for TrackBreadth<LengthOrPercentage> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
            return Ok(TrackBreadth::Breadth(lop))
        }

        if let Ok(f) = input.try(parse_flex) {
            return Ok(TrackBreadth::Fr(f))
        }

        TrackKeyword::parse(input).map(TrackBreadth::Keyword)
    }
}

impl Parse for TrackSize<LengthOrPercentage> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
            return Ok(TrackSize::Breadth(b))
        }

        if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
            return input.parse_nested_block(|input| {
                let inflexible_breadth =
                    match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
                        Ok(lop) => TrackBreadth::Breadth(lop),
                        Err(..) => {
                            let keyword = TrackKeyword::parse(input)?;
                            TrackBreadth::Keyword(keyword)
                        }
                    };

                input.expect_comma()?;
                Ok(TrackSize::Minmax(inflexible_breadth, TrackBreadth::parse(context, input)?))
            });
        }

        input.expect_function_matching("fit-content")?;
        let lop = input.parse_nested_block(|i| LengthOrPercentage::parse_non_negative(context, i))?;
        Ok(TrackSize::FitContent(lop))
    }
}

/// Parse the grid line names into a vector of owned strings.
///
/// <https://drafts.csswg.org/css-grid/#typedef-line-names>
pub fn parse_line_names<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Box<[CustomIdent]>, ParseError<'i>> {
    input.expect_square_bracket_block()?;
    input.parse_nested_block(|input| {
        let mut values = vec![];
        while let Ok((loc, ident)) = input.try(|i| -> Result<_, CssParseError<()>> {
             Ok((i.current_source_location(), i.expect_ident_cloned()?))
        }) {
            let ident = CustomIdent::from_ident(loc, &ident, &["span"])?;
            values.push(ident);
        }

        Ok(values.into_boxed_slice())
    })
}

/// The type of `repeat` function (only used in parsing).
///
/// <https://drafts.csswg.org/css-grid/#typedef-track-repeat>
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
enum RepeatType {
    /// [`<auto-repeat>`](https://drafts.csswg.org/css-grid/#typedef-auto-repeat)
    Auto,
    /// [`<track-repeat>`](https://drafts.csswg.org/css-grid/#typedef-track-repeat)
    Normal,
    /// [`<fixed-repeat>`](https://drafts.csswg.org/css-grid/#typedef-fixed-repeat)
    Fixed,
}

impl TrackRepeat<LengthOrPercentage, Integer> {
    fn parse_with_repeat_type<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<(Self, RepeatType), ParseError<'i>> {
        input.try(|i| i.expect_function_matching("repeat").map_err(|e| e.into())).and_then(|_| {
            input.parse_nested_block(|input| {
                let count = RepeatCount::parse(context, input)?;
                input.expect_comma()?;

                let is_auto = count == RepeatCount::AutoFit || count == RepeatCount::AutoFill;
                let mut repeat_type = if is_auto {
                    RepeatType::Auto
                } else {    // <fixed-size> is a subset of <track-size>, so it should work for both
                    RepeatType::Fixed
                };

                let mut names = vec![];
                let mut values = vec![];
                let mut current_names;

                loop {
                    current_names = input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice());
                    if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
                        if !track_size.is_fixed() {
                            if is_auto {
                                // should be <fixed-size> for <auto-repeat>
                                return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                            }

                            if repeat_type == RepeatType::Fixed {
                                repeat_type = RepeatType::Normal       // <track-size> for sure
                            }
                        }

                        values.push(track_size);
                        names.push(current_names);
                        if is_auto {
                            // FIXME: In the older version of the spec
                            // (https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-auto-repeat),
                            // if the repeat type is `<auto-repeat>` we shouldn't try to parse more than
                            // one `TrackSize`. But in current version of the spec, this is deprecated
                            // but we are adding this for gecko parity. We should remove this when
                            // gecko implements new spec.
                            names.push(input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice()));
                            break
                        }
                    } else {
                        if values.is_empty() {
                            // expecting at least one <track-size>
                            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                        }

                        names.push(current_names);      // final `<line-names>`
                        break       // no more <track-size>, breaking
                    }
                }

                let repeat = TrackRepeat {
                    count: count,
                    track_sizes: values,
                    line_names: names.into_boxed_slice(),
                };

                Ok((repeat, repeat_type))
            })
        })
    }
}

impl Parse for TrackList<LengthOrPercentage, Integer> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        let mut current_names = vec![];
        let mut names = vec![];
        let mut values = vec![];

        let mut list_type = TrackListType::Explicit;    // assume it's the simplest case
        // holds <auto-repeat> value. It can only be only one in a TrackList.
        let mut auto_repeat = None;
        // if there is any <auto-repeat> the list will be of type TrackListType::Auto(idx)
        // where idx points to the position of the <auto-repeat> in the track list. If there
        // is any repeat before <auto-repeat>, we need to take the number of repetitions into
        // account to set the position of <auto-repeat> so it remains the same while computing
        // values.
        let mut auto_offset = 0;
        // assume that everything is <fixed-size>. This flag is useful when we encounter <auto-repeat>
        let mut atleast_one_not_fixed = false;
        loop {
            current_names.extend_from_slice(&mut input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice()));
            if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
                if !track_size.is_fixed() {
                    atleast_one_not_fixed = true;
                    if auto_repeat.is_some() {
                        // <auto-track-list> only accepts <fixed-size> and <fixed-repeat>
                        return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                    }
                }

                let vec = mem::replace(&mut current_names, vec![]);
                names.push(vec.into_boxed_slice());
                values.push(TrackListValue::TrackSize(track_size));
            } else if let Ok((repeat, type_)) = input.try(|i| TrackRepeat::parse_with_repeat_type(context, i)) {
                if list_type == TrackListType::Explicit {
                    list_type = TrackListType::Normal;      // <explicit-track-list> doesn't contain repeat()
                }

                match type_ {
                    RepeatType::Normal => {
                        atleast_one_not_fixed = true;
                        if auto_repeat.is_some() { // only <fixed-repeat>
                            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                        }
                    },
                    RepeatType::Auto => {
                        if auto_repeat.is_some() || atleast_one_not_fixed {
                            // We've either seen <auto-repeat> earlier, or there's at least one non-fixed value
                            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                        }

                        list_type = TrackListType::Auto(values.len() as u16 + auto_offset);
                        auto_repeat = Some(repeat);
                        let vec = mem::replace(&mut current_names, vec![]);
                        names.push(vec.into_boxed_slice());
                        continue;
                    },
                    RepeatType::Fixed => (),
                }

                let vec = mem::replace(&mut current_names, vec![]);
                names.push(vec.into_boxed_slice());
                if let RepeatCount::Number(num) = repeat.count {
                    auto_offset += (num.value() - 1) as u16;
                }
                values.push(TrackListValue::TrackRepeat(repeat));
            } else {
                if values.is_empty() && auto_repeat.is_none() {
                    return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                }

                names.push(current_names.into_boxed_slice());
                break
            }
        }

        Ok(TrackList {
            list_type: list_type,
            values: values,
            line_names: names.into_boxed_slice(),
            auto_repeat: auto_repeat,
        })
    }
}

impl ToComputedValue for TrackList<LengthOrPercentage, Integer> {
    type ComputedValue = TrackList<computed::LengthOrPercentage, computed::Integer>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        // Merge the line names while computing values. The resulting values will
        // all be bunch of `<track-size>` and one <auto-repeat>.
        //
        // For example,
        // `[a b] 100px [c d] repeat(1, 30px [g]) [h]` will be merged as `[a b] 100px [c d] 30px [g h]`
        //  whereas, `[a b] repeat(2, [c] 50px [d]) [e f] repeat(auto-fill, [g] 12px) 10px [h]` will be merged as
        // `[a b c] 50px [d c] 50px [d e f] repeat(auto-fill, [g] 12px) 10px [h]`, with the `<auto-repeat>` value
        // set in the `auto_repeat` field, and the `idx` in TrackListType::Auto pointing to the values after
        // `<auto-repeat>` (in this case, `10px [h]`).
        let mut prev_names = vec![];
        let mut line_names = Vec::with_capacity(self.line_names.len() + 1);
        let mut values = Vec::with_capacity(self.values.len() + 1);
        for (pos, names) in self.line_names.iter().enumerate() {
            prev_names.extend_from_slice(&names);
            if pos >= self.values.len() {
                let vec = mem::replace(&mut prev_names, vec![]);
                line_names.push(vec.into_boxed_slice());
                continue;
            }

            match self.values[pos] {
                TrackListValue::TrackSize(ref size) => {
                    let vec = mem::replace(&mut prev_names, vec![]);
                    line_names.push(vec.into_boxed_slice());
                    values.push(TrackListValue::TrackSize(size.to_computed_value(context)));
                },
                TrackListValue::TrackRepeat(ref repeat) => {
                    // If the repeat count is numeric, we expand and merge the values.
                    let mut repeat = repeat.expand();
                    let mut repeat_names_iter = repeat.line_names.iter();
                    for (size, repeat_names) in repeat.track_sizes.drain(..).zip(&mut repeat_names_iter) {
                        prev_names.extend_from_slice(&repeat_names);
                        let vec = mem::replace(&mut prev_names, vec![]);
                        line_names.push(vec.into_boxed_slice());
                        values.push(TrackListValue::TrackSize(size.to_computed_value(context)));
                    }

                    if let Some(names) = repeat_names_iter.next() {
                        prev_names.extend_from_slice(&names);
                    }
                },
            }
        }

        TrackList {
            list_type: self.list_type.to_computed_value(context),
            values: values,
            line_names: line_names.into_boxed_slice(),
            auto_repeat: self.auto_repeat.clone().map(|repeat| repeat.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        let mut values = Vec::with_capacity(computed.values.len() + 1);
        for value in computed.values.iter().map(ToComputedValue::from_computed_value) {
            values.push(value);
        }

        TrackList {
            list_type: computed.list_type,
            values: values,
            line_names: computed.line_names.clone(),
            auto_repeat: computed.auto_repeat.clone().map(|ref repeat| TrackRepeat::from_computed_value(repeat)),
        }
    }
}

impl Parse for GridTemplateComponent<LengthOrPercentage, Integer> {
    // FIXME: Derive Parse (probably with None_)
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if input.try(|i| i.expect_ident_matching("none")).is_ok() {
            return Ok(GridTemplateComponent::None)
        }

        Self::parse_without_none(context, input)
    }
}

impl GridTemplateComponent<LengthOrPercentage, Integer> {
    /// Parses a `GridTemplateComponent<LengthOrPercentage>` except `none` keyword.
    pub fn parse_without_none<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        if let Ok(t) = input.try(|i| TrackList::parse(context, i)) {
            return Ok(GridTemplateComponent::TrackList(t))
        }

        LineNameList::parse(context, input).map(GridTemplateComponent::Subgrid)
    }
}
<commit_msg>stylo: Hide accidentally exposed subgrid behind prefs<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! CSS handling for the computed value of
//! [grids](https://drafts.csswg.org/css-grid/)

use cssparser::{Parser, Token, ParseError as CssParseError};
use parser::{Parse, ParserContext};
#[allow(unused_imports)] use std::ascii::AsciiExt;
use std::mem;
use style_traits::{ParseError, StyleParseErrorKind};
use values::{CSSFloat, CustomIdent};
use values::computed::{self, Context, ToComputedValue};
use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat};
use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType, TrackListValue};
use values::specified::{LengthOrPercentage, Integer};

/// Parse a single flexible length.
pub fn parse_flex<'i, 't>(input: &mut Parser<'i, 't>) -> Result<CSSFloat, ParseError<'i>> {
    let location = input.current_source_location();
    match *input.next()? {
        Token::Dimension { value, ref unit, .. } if unit.eq_ignore_ascii_case("fr") && value.is_sign_positive()
            => Ok(value),
        ref t => Err(location.new_unexpected_token_error(t.clone())),
    }
}

impl Parse for TrackBreadth<LengthOrPercentage> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
            return Ok(TrackBreadth::Breadth(lop))
        }

        if let Ok(f) = input.try(parse_flex) {
            return Ok(TrackBreadth::Fr(f))
        }

        TrackKeyword::parse(input).map(TrackBreadth::Keyword)
    }
}

impl Parse for TrackSize<LengthOrPercentage> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
            return Ok(TrackSize::Breadth(b))
        }

        if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
            return input.parse_nested_block(|input| {
                let inflexible_breadth =
                    match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
                        Ok(lop) => TrackBreadth::Breadth(lop),
                        Err(..) => {
                            let keyword = TrackKeyword::parse(input)?;
                            TrackBreadth::Keyword(keyword)
                        }
                    };

                input.expect_comma()?;
                Ok(TrackSize::Minmax(inflexible_breadth, TrackBreadth::parse(context, input)?))
            });
        }

        input.expect_function_matching("fit-content")?;
        let lop = input.parse_nested_block(|i| LengthOrPercentage::parse_non_negative(context, i))?;
        Ok(TrackSize::FitContent(lop))
    }
}

/// Parse the grid line names into a vector of owned strings.
///
/// <https://drafts.csswg.org/css-grid/#typedef-line-names>
pub fn parse_line_names<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Box<[CustomIdent]>, ParseError<'i>> {
    input.expect_square_bracket_block()?;
    input.parse_nested_block(|input| {
        let mut values = vec![];
        while let Ok((loc, ident)) = input.try(|i| -> Result<_, CssParseError<()>> {
             Ok((i.current_source_location(), i.expect_ident_cloned()?))
        }) {
            let ident = CustomIdent::from_ident(loc, &ident, &["span"])?;
            values.push(ident);
        }

        Ok(values.into_boxed_slice())
    })
}

/// The type of `repeat` function (only used in parsing).
///
/// <https://drafts.csswg.org/css-grid/#typedef-track-repeat>
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
enum RepeatType {
    /// [`<auto-repeat>`](https://drafts.csswg.org/css-grid/#typedef-auto-repeat)
    Auto,
    /// [`<track-repeat>`](https://drafts.csswg.org/css-grid/#typedef-track-repeat)
    Normal,
    /// [`<fixed-repeat>`](https://drafts.csswg.org/css-grid/#typedef-fixed-repeat)
    Fixed,
}

impl TrackRepeat<LengthOrPercentage, Integer> {
    fn parse_with_repeat_type<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<(Self, RepeatType), ParseError<'i>> {
        input.try(|i| i.expect_function_matching("repeat").map_err(|e| e.into())).and_then(|_| {
            input.parse_nested_block(|input| {
                let count = RepeatCount::parse(context, input)?;
                input.expect_comma()?;

                let is_auto = count == RepeatCount::AutoFit || count == RepeatCount::AutoFill;
                let mut repeat_type = if is_auto {
                    RepeatType::Auto
                } else {    // <fixed-size> is a subset of <track-size>, so it should work for both
                    RepeatType::Fixed
                };

                let mut names = vec![];
                let mut values = vec![];
                let mut current_names;

                loop {
                    current_names = input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice());
                    if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
                        if !track_size.is_fixed() {
                            if is_auto {
                                // should be <fixed-size> for <auto-repeat>
                                return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                            }

                            if repeat_type == RepeatType::Fixed {
                                repeat_type = RepeatType::Normal       // <track-size> for sure
                            }
                        }

                        values.push(track_size);
                        names.push(current_names);
                        if is_auto {
                            // FIXME: In the older version of the spec
                            // (https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-auto-repeat),
                            // if the repeat type is `<auto-repeat>` we shouldn't try to parse more than
                            // one `TrackSize`. But in current version of the spec, this is deprecated
                            // but we are adding this for gecko parity. We should remove this when
                            // gecko implements new spec.
                            names.push(input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice()));
                            break
                        }
                    } else {
                        if values.is_empty() {
                            // expecting at least one <track-size>
                            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                        }

                        names.push(current_names);      // final `<line-names>`
                        break       // no more <track-size>, breaking
                    }
                }

                let repeat = TrackRepeat {
                    count: count,
                    track_sizes: values,
                    line_names: names.into_boxed_slice(),
                };

                Ok((repeat, repeat_type))
            })
        })
    }
}

impl Parse for TrackList<LengthOrPercentage, Integer> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        let mut current_names = vec![];
        let mut names = vec![];
        let mut values = vec![];

        let mut list_type = TrackListType::Explicit;    // assume it's the simplest case
        // holds <auto-repeat> value. It can only be only one in a TrackList.
        let mut auto_repeat = None;
        // if there is any <auto-repeat> the list will be of type TrackListType::Auto(idx)
        // where idx points to the position of the <auto-repeat> in the track list. If there
        // is any repeat before <auto-repeat>, we need to take the number of repetitions into
        // account to set the position of <auto-repeat> so it remains the same while computing
        // values.
        let mut auto_offset = 0;
        // assume that everything is <fixed-size>. This flag is useful when we encounter <auto-repeat>
        let mut atleast_one_not_fixed = false;
        loop {
            current_names.extend_from_slice(&mut input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice()));
            if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
                if !track_size.is_fixed() {
                    atleast_one_not_fixed = true;
                    if auto_repeat.is_some() {
                        // <auto-track-list> only accepts <fixed-size> and <fixed-repeat>
                        return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                    }
                }

                let vec = mem::replace(&mut current_names, vec![]);
                names.push(vec.into_boxed_slice());
                values.push(TrackListValue::TrackSize(track_size));
            } else if let Ok((repeat, type_)) = input.try(|i| TrackRepeat::parse_with_repeat_type(context, i)) {
                if list_type == TrackListType::Explicit {
                    list_type = TrackListType::Normal;      // <explicit-track-list> doesn't contain repeat()
                }

                match type_ {
                    RepeatType::Normal => {
                        atleast_one_not_fixed = true;
                        if auto_repeat.is_some() { // only <fixed-repeat>
                            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                        }
                    },
                    RepeatType::Auto => {
                        if auto_repeat.is_some() || atleast_one_not_fixed {
                            // We've either seen <auto-repeat> earlier, or there's at least one non-fixed value
                            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                        }

                        list_type = TrackListType::Auto(values.len() as u16 + auto_offset);
                        auto_repeat = Some(repeat);
                        let vec = mem::replace(&mut current_names, vec![]);
                        names.push(vec.into_boxed_slice());
                        continue;
                    },
                    RepeatType::Fixed => (),
                }

                let vec = mem::replace(&mut current_names, vec![]);
                names.push(vec.into_boxed_slice());
                if let RepeatCount::Number(num) = repeat.count {
                    auto_offset += (num.value() - 1) as u16;
                }
                values.push(TrackListValue::TrackRepeat(repeat));
            } else {
                if values.is_empty() && auto_repeat.is_none() {
                    return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                }

                names.push(current_names.into_boxed_slice());
                break
            }
        }

        Ok(TrackList {
            list_type: list_type,
            values: values,
            line_names: names.into_boxed_slice(),
            auto_repeat: auto_repeat,
        })
    }
}

impl ToComputedValue for TrackList<LengthOrPercentage, Integer> {
    type ComputedValue = TrackList<computed::LengthOrPercentage, computed::Integer>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        // Merge the line names while computing values. The resulting values will
        // all be bunch of `<track-size>` and one <auto-repeat>.
        //
        // For example,
        // `[a b] 100px [c d] repeat(1, 30px [g]) [h]` will be merged as `[a b] 100px [c d] 30px [g h]`
        //  whereas, `[a b] repeat(2, [c] 50px [d]) [e f] repeat(auto-fill, [g] 12px) 10px [h]` will be merged as
        // `[a b c] 50px [d c] 50px [d e f] repeat(auto-fill, [g] 12px) 10px [h]`, with the `<auto-repeat>` value
        // set in the `auto_repeat` field, and the `idx` in TrackListType::Auto pointing to the values after
        // `<auto-repeat>` (in this case, `10px [h]`).
        let mut prev_names = vec![];
        let mut line_names = Vec::with_capacity(self.line_names.len() + 1);
        let mut values = Vec::with_capacity(self.values.len() + 1);
        for (pos, names) in self.line_names.iter().enumerate() {
            prev_names.extend_from_slice(&names);
            if pos >= self.values.len() {
                let vec = mem::replace(&mut prev_names, vec![]);
                line_names.push(vec.into_boxed_slice());
                continue;
            }

            match self.values[pos] {
                TrackListValue::TrackSize(ref size) => {
                    let vec = mem::replace(&mut prev_names, vec![]);
                    line_names.push(vec.into_boxed_slice());
                    values.push(TrackListValue::TrackSize(size.to_computed_value(context)));
                },
                TrackListValue::TrackRepeat(ref repeat) => {
                    // If the repeat count is numeric, we expand and merge the values.
                    let mut repeat = repeat.expand();
                    let mut repeat_names_iter = repeat.line_names.iter();
                    for (size, repeat_names) in repeat.track_sizes.drain(..).zip(&mut repeat_names_iter) {
                        prev_names.extend_from_slice(&repeat_names);
                        let vec = mem::replace(&mut prev_names, vec![]);
                        line_names.push(vec.into_boxed_slice());
                        values.push(TrackListValue::TrackSize(size.to_computed_value(context)));
                    }

                    if let Some(names) = repeat_names_iter.next() {
                        prev_names.extend_from_slice(&names);
                    }
                },
            }
        }

        TrackList {
            list_type: self.list_type.to_computed_value(context),
            values: values,
            line_names: line_names.into_boxed_slice(),
            auto_repeat: self.auto_repeat.clone().map(|repeat| repeat.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        let mut values = Vec::with_capacity(computed.values.len() + 1);
        for value in computed.values.iter().map(ToComputedValue::from_computed_value) {
            values.push(value);
        }

        TrackList {
            list_type: computed.list_type,
            values: values,
            line_names: computed.line_names.clone(),
            auto_repeat: computed.auto_repeat.clone().map(|ref repeat| TrackRepeat::from_computed_value(repeat)),
        }
    }
}

#[cfg(feature = "gecko")]
#[inline]
fn allow_grid_template_subgrids() -> bool {
    use gecko_bindings::structs::mozilla;
    unsafe { mozilla::StylePrefs_sGridTemplateSubgridValueEnabled }
}

#[cfg(feature = "servo")]
#[inline]
fn allow_grid_template_subgrids() -> bool {
    false
}

impl Parse for GridTemplateComponent<LengthOrPercentage, Integer> {
    // FIXME: Derive Parse (probably with None_)
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if input.try(|i| i.expect_ident_matching("none")).is_ok() {
            return Ok(GridTemplateComponent::None)
        }

        Self::parse_without_none(context, input)
    }
}

impl GridTemplateComponent<LengthOrPercentage, Integer> {
    /// Parses a `GridTemplateComponent<LengthOrPercentage>` except `none` keyword.
    pub fn parse_without_none<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        if allow_grid_template_subgrids() {
            if let Ok(t) = input.try(|i| LineNameList::parse(context, i)) {
                return Ok(GridTemplateComponent::Subgrid(t))
            }
        }

        TrackList::parse(context, input).map(GridTemplateComponent::TrackList)
    }
}
<|endoftext|>