<commit_before>// Copyright 2018 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.

/*!
This crate provides a robust regular expression parser.

This crate defines two primary types:

* [`Ast`](ast/enum.Ast.html) is the abstract syntax of a regular expression.
  An abstract syntax corresponds to a *structured representation* of the
  concrete syntax of a regular expression, where the concrete syntax is the
  pattern string itself (e.g., `foo(bar)+`). Given some abstract syntax, it
  can be converted back to the original concrete syntax (modulo some details,
  like whitespace). To a first approximation, the abstract syntax is complex
  and difficult to analyze.
* [`Hir`](hir/struct.Hir.html) is the high-level intermediate representation
  ("HIR" or "high-level IR" for short) of regular expression. It corresponds to
  an intermediate state of a regular expression that sits between the abstract
  syntax and the low level compiled opcodes that are eventually responsible for
  executing a regular expression search. Given some high-level IR, it is not
  possible to produce the original concrete syntax (although it is possible to
  produce an equivalent conrete syntax, but it will likely scarcely resemble
  the original pattern). To a first approximation, the high-level IR is simple
  and easy to analyze.

These two types come with conversion routines:

* An [`ast::parse::Parser`](ast/parse/struct.Parser.html) converts concrete
  syntax (a `&str`) to an [`Ast`](ast/enum.Ast.html).
* A [`hir::translate::Translator`](hir/translate/struct.Translator.html)
  converts an [`Ast`](ast/enum.Ast.html) to a [`Hir`](hir/struct.Hir.html).

As a convenience, the above two conversion routines are combined into one via
the top-level [`Parser`](struct.Parser.html) type. This `Parser` will first
convert your pattern to an `Ast` and then convert the `Ast` to an `Hir`.

# Example

This example shows how to parse a pattern string into its HIR:

```
use regex_syntax::Parser;
use regex_syntax::hir::{self, Hir};

let hir = Parser::new().parse("a|b").unwrap();
assert_eq!(hir, Hir::alternation(vec![
    Hir::literal(hir::Literal::Unicode('a')),
    Hir::literal(hir::Literal::Unicode('b')),
]));
```

# Concrete syntax supported

The concrete syntax is documented as part of the public API of the
[`regex` crate](https://docs.rs/regex/%2A/regex/#syntax).

# Input safety

A key feature of this library is that it is safe to use with end user facing
input. This plays a significant role in the internal implementation. In
particular:

1. Parsers provide a `nest_limit` option that permits callers to control how
   deeply nested a regular expression is allowed to be. This makes it possible
   to do case analysis over an `Ast` or an `Hir` using recursion without
   worrying about stack overflow.
2. Since relying on a particular stack size is brittle, this crate goes to
   great lengths to ensure that all interactions with both the `Ast` and the
   `Hir` do not use recursion. Namely, they use constant stack space and heap
   space proportional to the size of the original pattern string (in bytes).
   This includes the type's corresponding destructors. (One exception to this
   is literal extraction, but this will eventually get fixed.)

# Error reporting

The `Display` implementations on all `Error` types exposed in this library
provide nice human readable errors that are suitable for showing to end users
in a monospace font.

# Literal extraction

This crate provides limited support for
[literal extraction from `Hir` values](hir/literal/struct.Literals.html).
Be warned that literal extraction currently uses recursion, and therefore,
stack size proportional to the size of the `Hir`.

The purpose of literal extraction is to speed up searches. That is, if you
know a regular expression must match a prefix or suffix literal, then it is
often quicker to search for instances of that literal, and then confirm or deny
the match using the full regular expression engine. These optimizations are
done automatically in the `regex` crate.
*/

#![deny(missing_docs)]
#![allow(ellipsis_inclusive_range_patterns)]

extern crate ucd_util;

pub use error::{Error, Result};
pub use parser::{Parser, ParserBuilder};

pub mod ast;
mod either;
mod error;
pub mod hir;
mod parser;
mod unicode;
mod unicode_tables;

/// Escapes all regular expression meta characters in `text`.
///
/// The string returned may be safely used as a literal in a regular
/// expression.
pub fn escape(text: &str) -> String {
    let mut quoted = String::with_capacity(text.len());
    escape_into(text, &mut quoted);
    quoted
}

/// Escapes all meta characters in `text` and writes the result into `buf`.
///
/// This will append escape characters into the given buffer. The characters
/// that are appended are safe to use as a literal in a regular expression.
pub fn escape_into(text: &str, buf: &mut String) {
    for c in text.chars() {
        if is_meta_character(c) {
            buf.push('\\');
        }
        buf.push(c);
    }
}

/// Returns true if the give character has significance in a regex.
///
/// These are the only characters that are allowed to be escaped, with one
/// exception: an ASCII space character may be escaped when extended mode (with
/// the `x` flag) is enabld. In particular, `is_meta_character(' ')` returns
/// `false`.
///
/// Note that the set of characters for which this function returns `true` or
/// `false` is fixed and won't change in a semver compatible release.
pub fn is_meta_character(c: char) -> bool {
    match c {
        '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' |
        '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~' => true,
        _ => false,
    }
}

/// Returns true if and only if the given character is a Unicode word
/// character.
///
/// A Unicode word character is defined by
/// [UTS#18 Annex C](http://unicode.org/reports/tr18/#Compatibility_Properties).
/// In particular, a character
/// is considered a word character if it is in either of the `Alphabetic` or
/// `Join_Control` properties, or is in one of the `Decimal_Number`, `Mark`
/// or `Connector_Punctuation` general categories.
pub fn is_word_character(c: char) -> bool {
    use std::cmp::Ordering;
    use unicode_tables::perl_word::PERL_WORD;

    if c <= 0x7F as char && is_word_byte(c as u8) {
        return true;
    }
    PERL_WORD
        .binary_search_by(|&(start, end)| {
            if start <= c && c <= end {
                Ordering::Equal
            } else if start > c {
                Ordering::Greater
            } else {
                Ordering::Less
            }
        }).is_ok()
}

/// Returns true if and only if the given character is an ASCII word character.
///
/// An ASCII word character is defined by the following character class:
/// `[_0-9a-zA-Z]'.
pub fn is_word_byte(c: u8) -> bool {
    match c {
        b'_' | b'0' ... b'9' | b'a' ... b'z' | b'A' ... b'Z'  => true,
        _ => false,
    }
}

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

    #[test]
    fn escape_meta() {
        assert_eq!(
            escape(r"\.+*?()|[]{}^$#&-~"),
            r"\\\.\+\*\?\(\)\|\[\]\{\}\^\$\#\&\-\~".to_string());
    }

    #[test]
    fn word() {
        assert!(is_word_byte(b'a'));
        assert!(!is_word_byte(b'-'));

        assert!(is_word_character('a'), "ASCII");
        assert!(is_word_character('à'), "Latin-1");
        assert!(is_word_character('β'), "Greek");
        assert!(is_word_character('\u{11011}'), "Brahmi (Unicode 6.0)");
        assert!(is_word_character('\u{11611}'), "Modi (Unicode 7.0)");
        assert!(is_word_character('\u{11711}'), "Ahom (Unicode 8.0)");
        assert!(is_word_character('\u{17828}'), "Tangut (Unicode 9.0)");
        assert!(is_word_character('\u{1B1B1}'), "Nushu (Unicode 10.0)");
        assert!(is_word_character('\u{16E40}'), "Medefaidrin (Unicode 11.0)");
        assert!(!is_word_character('-'));
        assert!(!is_word_character('☃'));
    }
}
<commit_msg>syntax/doc: fix typo<commit_after>// Copyright 2018 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.

/*!
This crate provides a robust regular expression parser.

This crate defines two primary types:

* [`Ast`](ast/enum.Ast.html) is the abstract syntax of a regular expression.
  An abstract syntax corresponds to a *structured representation* of the
  concrete syntax of a regular expression, where the concrete syntax is the
  pattern string itself (e.g., `foo(bar)+`). Given some abstract syntax, it
  can be converted back to the original concrete syntax (modulo some details,
  like whitespace). To a first approximation, the abstract syntax is complex
  and difficult to analyze.
* [`Hir`](hir/struct.Hir.html) is the high-level intermediate representation
  ("HIR" or "high-level IR" for short) of regular expression. It corresponds to
  an intermediate state of a regular expression that sits between the abstract
  syntax and the low level compiled opcodes that are eventually responsible for
  executing a regular expression search. Given some high-level IR, it is not
  possible to produce the original concrete syntax (although it is possible to
  produce an equivalent concrete syntax, but it will likely scarcely resemble
  the original pattern). To a first approximation, the high-level IR is simple
  and easy to analyze.

These two types come with conversion routines:

* An [`ast::parse::Parser`](ast/parse/struct.Parser.html) converts concrete
  syntax (a `&str`) to an [`Ast`](ast/enum.Ast.html).
* A [`hir::translate::Translator`](hir/translate/struct.Translator.html)
  converts an [`Ast`](ast/enum.Ast.html) to a [`Hir`](hir/struct.Hir.html).

As a convenience, the above two conversion routines are combined into one via
the top-level [`Parser`](struct.Parser.html) type. This `Parser` will first
convert your pattern to an `Ast` and then convert the `Ast` to an `Hir`.

# Example

This example shows how to parse a pattern string into its HIR:

```
use regex_syntax::Parser;
use regex_syntax::hir::{self, Hir};

let hir = Parser::new().parse("a|b").unwrap();
assert_eq!(hir, Hir::alternation(vec![
    Hir::literal(hir::Literal::Unicode('a')),
    Hir::literal(hir::Literal::Unicode('b')),
]));
```

# Concrete syntax supported

The concrete syntax is documented as part of the public API of the
[`regex` crate](https://docs.rs/regex/%2A/regex/#syntax).

# Input safety

A key feature of this library is that it is safe to use with end user facing
input. This plays a significant role in the internal implementation. In
particular:

1. Parsers provide a `nest_limit` option that permits callers to control how
   deeply nested a regular expression is allowed to be. This makes it possible
   to do case analysis over an `Ast` or an `Hir` using recursion without
   worrying about stack overflow.
2. Since relying on a particular stack size is brittle, this crate goes to
   great lengths to ensure that all interactions with both the `Ast` and the
   `Hir` do not use recursion. Namely, they use constant stack space and heap
   space proportional to the size of the original pattern string (in bytes).
   This includes the type's corresponding destructors. (One exception to this
   is literal extraction, but this will eventually get fixed.)

# Error reporting

The `Display` implementations on all `Error` types exposed in this library
provide nice human readable errors that are suitable for showing to end users
in a monospace font.

# Literal extraction

This crate provides limited support for
[literal extraction from `Hir` values](hir/literal/struct.Literals.html).
Be warned that literal extraction currently uses recursion, and therefore,
stack size proportional to the size of the `Hir`.

The purpose of literal extraction is to speed up searches. That is, if you
know a regular expression must match a prefix or suffix literal, then it is
often quicker to search for instances of that literal, and then confirm or deny
the match using the full regular expression engine. These optimizations are
done automatically in the `regex` crate.
*/

#![deny(missing_docs)]
#![allow(ellipsis_inclusive_range_patterns)]

extern crate ucd_util;

pub use error::{Error, Result};
pub use parser::{Parser, ParserBuilder};

pub mod ast;
mod either;
mod error;
pub mod hir;
mod parser;
mod unicode;
mod unicode_tables;

/// Escapes all regular expression meta characters in `text`.
///
/// The string returned may be safely used as a literal in a regular
/// expression.
pub fn escape(text: &str) -> String {
    let mut quoted = String::with_capacity(text.len());
    escape_into(text, &mut quoted);
    quoted
}

/// Escapes all meta characters in `text` and writes the result into `buf`.
///
/// This will append escape characters into the given buffer. The characters
/// that are appended are safe to use as a literal in a regular expression.
pub fn escape_into(text: &str, buf: &mut String) {
    for c in text.chars() {
        if is_meta_character(c) {
            buf.push('\\');
        }
        buf.push(c);
    }
}

/// Returns true if the give character has significance in a regex.
///
/// These are the only characters that are allowed to be escaped, with one
/// exception: an ASCII space character may be escaped when extended mode (with
/// the `x` flag) is enabld. In particular, `is_meta_character(' ')` returns
/// `false`.
///
/// Note that the set of characters for which this function returns `true` or
/// `false` is fixed and won't change in a semver compatible release.
pub fn is_meta_character(c: char) -> bool {
    match c {
        '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' |
        '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~' => true,
        _ => false,
    }
}

/// Returns true if and only if the given character is a Unicode word
/// character.
///
/// A Unicode word character is defined by
/// [UTS#18 Annex C](http://unicode.org/reports/tr18/#Compatibility_Properties).
/// In particular, a character
/// is considered a word character if it is in either of the `Alphabetic` or
/// `Join_Control` properties, or is in one of the `Decimal_Number`, `Mark`
/// or `Connector_Punctuation` general categories.
pub fn is_word_character(c: char) -> bool {
    use std::cmp::Ordering;
    use unicode_tables::perl_word::PERL_WORD;

    if c <= 0x7F as char && is_word_byte(c as u8) {
        return true;
    }
    PERL_WORD
        .binary_search_by(|&(start, end)| {
            if start <= c && c <= end {
                Ordering::Equal
            } else if start > c {
                Ordering::Greater
            } else {
                Ordering::Less
            }
        }).is_ok()
}

/// Returns true if and only if the given character is an ASCII word character.
///
/// An ASCII word character is defined by the following character class:
/// `[_0-9a-zA-Z]'.
pub fn is_word_byte(c: u8) -> bool {
    match c {
        b'_' | b'0' ... b'9' | b'a' ... b'z' | b'A' ... b'Z'  => true,
        _ => false,
    }
}

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

    #[test]
    fn escape_meta() {
        assert_eq!(
            escape(r"\.+*?()|[]{}^$#&-~"),
            r"\\\.\+\*\?\(\)\|\[\]\{\}\^\$\#\&\-\~".to_string());
    }

    #[test]
    fn word() {
        assert!(is_word_byte(b'a'));
        assert!(!is_word_byte(b'-'));

        assert!(is_word_character('a'), "ASCII");
        assert!(is_word_character('à'), "Latin-1");
        assert!(is_word_character('β'), "Greek");
        assert!(is_word_character('\u{11011}'), "Brahmi (Unicode 6.0)");
        assert!(is_word_character('\u{11611}'), "Modi (Unicode 7.0)");
        assert!(is_word_character('\u{11711}'), "Ahom (Unicode 8.0)");
        assert!(is_word_character('\u{17828}'), "Tangut (Unicode 9.0)");
        assert!(is_word_character('\u{1B1B1}'), "Nushu (Unicode 10.0)");
        assert!(is_word_character('\u{16E40}'), "Medefaidrin (Unicode 11.0)");
        assert!(!is_word_character('-'));
        assert!(!is_word_character('☃'));
    }
}
<|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/. */

//! Data needed by the layout task.

use css::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};

use geom::rect::Rect;
use geom::size::Size2D;
use gfx::display_list::OpaqueNode;
use gfx::font_context::{FontContext, FontContextInfo};
#[cfg(not(target_os="android"))]
use green::task::GreenTask;
use script::layout_interface::LayoutChan;
use servo_msg::constellation_msg::ConstellationChan;
use servo_net::image::holder::LocalImageCacheHandle;
use servo_util::geometry::Au;
use servo_util::opts::Opts;
use std::mem;
#[cfg(not(target_os="android"))]
use std::ptr;
#[cfg(not(target_os="android"))]
use std::rt::local::Local;
#[cfg(not(target_os="android"))]
use std::rt::task::Task;
use style::Stylist;
use url::Url;

#[cfg(not(target_os="android"))]
#[thread_local]
static mut FONT_CONTEXT: *mut FontContext = 0 as *mut FontContext;

#[cfg(target_os="android")]
local_data_key!(font_context: *mut FontContext)

#[cfg(not(target_os="android"))]
#[thread_local]
static mut APPLICABLE_DECLARATIONS_CACHE: *mut ApplicableDeclarationsCache =
    0 as *mut ApplicableDeclarationsCache;

#[cfg(target_os="android")]
local_data_key!(applicable_declarations_cache: *mut ApplicableDeclarationsCache)

#[cfg(not(target_os="android"))]
#[thread_local]
static mut STYLE_SHARING_CANDIDATE_CACHE: *mut StyleSharingCandidateCache =
    0 as *mut StyleSharingCandidateCache;

#[cfg(target_os="android")]
local_data_key!(style_sharing_candidate_cache: *mut StyleSharingCandidateCache)

/// Data shared by all layout workers.
#[deriving(Clone)]
pub struct LayoutContext {
    /// The local image cache.
    pub image_cache: LocalImageCacheHandle,

    /// The current screen size.
    pub screen_size: Size2D<Au>,

    /// A channel up to the constellation.
    pub constellation_chan: ConstellationChan,

    /// A channel up to the layout task.
    pub layout_chan: LayoutChan,

    /// Information needed to construct a font context.
    pub font_context_info: FontContextInfo,

    /// The CSS selector stylist.
    ///
    /// FIXME(pcwalton): Make this no longer an unsafe pointer once we have fast `RWArc`s.
    pub stylist: *Stylist,

    /// The root node at which we're starting the layout.
    pub reflow_root: OpaqueNode,

    /// The URL.
    pub url: Url,

    /// The command line options.
    pub opts: Opts,

    /// The dirty rectangle, used during display list building.
    pub dirty: Rect<Au>,
}

#[cfg(not(target_os="android"))]
impl LayoutContext {
    pub fn font_context<'a>(&'a mut self) -> &'a mut FontContext {
        // Sanity check.
        {
            let mut task = Local::borrow(None::<Task>);
            match task.maybe_take_runtime::<GreenTask>() {
                Some(green) => {
                    task.put_runtime(green);
                    fail!("can't call this on a green task!")
                }
                None => {}
            }
        }

        unsafe {
            if FONT_CONTEXT == ptr::mut_null() {
                let context = box FontContext::new(self.font_context_info.clone());
                FONT_CONTEXT = mem::transmute(context)
            }
            mem::transmute(FONT_CONTEXT)
        }
    }

    pub fn applicable_declarations_cache<'a>(&'a self) -> &'a mut ApplicableDeclarationsCache {
        // Sanity check.
        {
            let mut task = Local::borrow(None::<Task>);
            match task.maybe_take_runtime::<GreenTask>() {
                Some(green) => {
                    task.put_runtime(green);
                    fail!("can't call this on a green task!")
                }
                None => {}
            }
        }

        unsafe {
            if APPLICABLE_DECLARATIONS_CACHE == ptr::mut_null() {
                let cache = box ApplicableDeclarationsCache::new();
                APPLICABLE_DECLARATIONS_CACHE = mem::transmute(cache)
            }
            mem::transmute(APPLICABLE_DECLARATIONS_CACHE)
        }
    }

    pub fn style_sharing_candidate_cache<'a>(&'a self) -> &'a mut StyleSharingCandidateCache {
        // Sanity check.
        {
            let mut task = Local::borrow(None::<Task>);
            match task.maybe_take_runtime::<GreenTask>() {
                Some(green) => {
                    task.put_runtime(green);
                    fail!("can't call this on a green task!")
                }
                None => {}
            }
        }

        unsafe {
            if STYLE_SHARING_CANDIDATE_CACHE == ptr::mut_null() {
                let cache = box StyleSharingCandidateCache::new();
                STYLE_SHARING_CANDIDATE_CACHE = mem::transmute(cache)
            }
            mem::transmute(STYLE_SHARING_CANDIDATE_CACHE)
        }
    }
}

// On Android, we don't have the __tls_* functions emitted by rustc, so we
// need to use the slower local_data functions.
// Making matters worse, the local_data functions are very particular about
// enforcing the lifetimes associated with objects that they hold onto,
// which causes us some trouble we work around as below.
#[cfg(target_os="android")]
impl LayoutContext {
    pub fn font_context<'a>(&'a mut self) -> &'a mut FontContext {
        unsafe {
            let opt = font_context.replace(None);
            let mut context;
            match opt {
                Some(c) => context = mem::transmute(c),
                None => {
                    context = mem::transmute(box FontContext::new(self.font_context_info.clone()))
                }
            }
            font_context.replace(Some(context));
            mem::transmute(context)
        }
    }

    pub fn applicable_declarations_cache<'a>(&'a self) -> &'a mut ApplicableDeclarationsCache {
        unsafe {
            let opt = applicable_declarations_cache.replace(None);
            let mut cache;
            match opt {
                Some(c) => cache = mem::transmute(c),
                None => {
                    cache = mem::transmute(box ApplicableDeclarationsCache::new());
                }
            }
            applicable_declarations_cache.replace(Some(cache));
            mem::transmute(cache)
        }
    }

    pub fn style_sharing_candidate_cache<'a>(&'a self) -> &'a mut StyleSharingCandidateCache {
        unsafe {
            let opt = style_sharing_candidate_cache.replace(None);
            let mut cache;
            match opt {
                Some(c) => cache = mem::transmute(c),
                None => {
                    cache = mem::transmute(box StyleSharingCandidateCache::new());
                }
            }
            style_sharing_candidate_cache.replace(Some(cache));
            mem::transmute(cache)
        }
    }
}

<commit_msg>Add an issue number to a FIXME comment.<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/. */

//! Data needed by the layout task.

use css::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};

use geom::rect::Rect;
use geom::size::Size2D;
use gfx::display_list::OpaqueNode;
use gfx::font_context::{FontContext, FontContextInfo};
#[cfg(not(target_os="android"))]
use green::task::GreenTask;
use script::layout_interface::LayoutChan;
use servo_msg::constellation_msg::ConstellationChan;
use servo_net::image::holder::LocalImageCacheHandle;
use servo_util::geometry::Au;
use servo_util::opts::Opts;
use std::mem;
#[cfg(not(target_os="android"))]
use std::ptr;
#[cfg(not(target_os="android"))]
use std::rt::local::Local;
#[cfg(not(target_os="android"))]
use std::rt::task::Task;
use style::Stylist;
use url::Url;

#[cfg(not(target_os="android"))]
#[thread_local]
static mut FONT_CONTEXT: *mut FontContext = 0 as *mut FontContext;

#[cfg(target_os="android")]
local_data_key!(font_context: *mut FontContext)

#[cfg(not(target_os="android"))]
#[thread_local]
static mut APPLICABLE_DECLARATIONS_CACHE: *mut ApplicableDeclarationsCache =
    0 as *mut ApplicableDeclarationsCache;

#[cfg(target_os="android")]
local_data_key!(applicable_declarations_cache: *mut ApplicableDeclarationsCache)

#[cfg(not(target_os="android"))]
#[thread_local]
static mut STYLE_SHARING_CANDIDATE_CACHE: *mut StyleSharingCandidateCache =
    0 as *mut StyleSharingCandidateCache;

#[cfg(target_os="android")]
local_data_key!(style_sharing_candidate_cache: *mut StyleSharingCandidateCache)

/// Data shared by all layout workers.
#[deriving(Clone)]
pub struct LayoutContext {
    /// The local image cache.
    pub image_cache: LocalImageCacheHandle,

    /// The current screen size.
    pub screen_size: Size2D<Au>,

    /// A channel up to the constellation.
    pub constellation_chan: ConstellationChan,

    /// A channel up to the layout task.
    pub layout_chan: LayoutChan,

    /// Information needed to construct a font context.
    pub font_context_info: FontContextInfo,

    /// The CSS selector stylist.
    ///
    /// FIXME(#2604): Make this no longer an unsafe pointer once we have fast `RWArc`s.
    pub stylist: *Stylist,

    /// The root node at which we're starting the layout.
    pub reflow_root: OpaqueNode,

    /// The URL.
    pub url: Url,

    /// The command line options.
    pub opts: Opts,

    /// The dirty rectangle, used during display list building.
    pub dirty: Rect<Au>,
}

#[cfg(not(target_os="android"))]
impl LayoutContext {
    pub fn font_context<'a>(&'a mut self) -> &'a mut FontContext {
        // Sanity check.
        {
            let mut task = Local::borrow(None::<Task>);
            match task.maybe_take_runtime::<GreenTask>() {
                Some(green) => {
                    task.put_runtime(green);
                    fail!("can't call this on a green task!")
                }
                None => {}
            }
        }

        unsafe {
            if FONT_CONTEXT == ptr::mut_null() {
                let context = box FontContext::new(self.font_context_info.clone());
                FONT_CONTEXT = mem::transmute(context)
            }
            mem::transmute(FONT_CONTEXT)
        }
    }

    pub fn applicable_declarations_cache<'a>(&'a self) -> &'a mut ApplicableDeclarationsCache {
        // Sanity check.
        {
            let mut task = Local::borrow(None::<Task>);
            match task.maybe_take_runtime::<GreenTask>() {
                Some(green) => {
                    task.put_runtime(green);
                    fail!("can't call this on a green task!")
                }
                None => {}
            }
        }

        unsafe {
            if APPLICABLE_DECLARATIONS_CACHE == ptr::mut_null() {
                let cache = box ApplicableDeclarationsCache::new();
                APPLICABLE_DECLARATIONS_CACHE = mem::transmute(cache)
            }
            mem::transmute(APPLICABLE_DECLARATIONS_CACHE)
        }
    }

    pub fn style_sharing_candidate_cache<'a>(&'a self) -> &'a mut StyleSharingCandidateCache {
        // Sanity check.
        {
            let mut task = Local::borrow(None::<Task>);
            match task.maybe_take_runtime::<GreenTask>() {
                Some(green) => {
                    task.put_runtime(green);
                    fail!("can't call this on a green task!")
                }
                None => {}
            }
        }

        unsafe {
            if STYLE_SHARING_CANDIDATE_CACHE == ptr::mut_null() {
                let cache = box StyleSharingCandidateCache::new();
                STYLE_SHARING_CANDIDATE_CACHE = mem::transmute(cache)
            }
            mem::transmute(STYLE_SHARING_CANDIDATE_CACHE)
        }
    }
}

// On Android, we don't have the __tls_* functions emitted by rustc, so we
// need to use the slower local_data functions.
// Making matters worse, the local_data functions are very particular about
// enforcing the lifetimes associated with objects that they hold onto,
// which causes us some trouble we work around as below.
#[cfg(target_os="android")]
impl LayoutContext {
    pub fn font_context<'a>(&'a mut self) -> &'a mut FontContext {
        unsafe {
            let opt = font_context.replace(None);
            let mut context;
            match opt {
                Some(c) => context = mem::transmute(c),
                None => {
                    context = mem::transmute(box FontContext::new(self.font_context_info.clone()))
                }
            }
            font_context.replace(Some(context));
            mem::transmute(context)
        }
    }

    pub fn applicable_declarations_cache<'a>(&'a self) -> &'a mut ApplicableDeclarationsCache {
        unsafe {
            let opt = applicable_declarations_cache.replace(None);
            let mut cache;
            match opt {
                Some(c) => cache = mem::transmute(c),
                None => {
                    cache = mem::transmute(box ApplicableDeclarationsCache::new());
                }
            }
            applicable_declarations_cache.replace(Some(cache));
            mem::transmute(cache)
        }
    }

    pub fn style_sharing_candidate_cache<'a>(&'a self) -> &'a mut StyleSharingCandidateCache {
        unsafe {
            let opt = style_sharing_candidate_cache.replace(None);
            let mut cache;
            match opt {
                Some(c) => cache = mem::transmute(c),
                None => {
                    cache = mem::transmute(box StyleSharingCandidateCache::new());
                }
            }
            style_sharing_candidate_cache.replace(Some(cache));
            mem::transmute(cache)
        }
    }
}

<|endoftext|>


<commit_before>use core::arch::x86_64 as arch;
use rand::prelude::*;
use std::env;
use std::f64::consts::PI;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::net::{TcpListener, TcpStream};
use std::str;
use std::thread;
use std::time::Instant;
use std::vec;

mod laplace;
mod matmul;

pub use matmul::test_matmul_strassen;

pub fn random_number() -> Result<(), ()> {
	let mut rng = rand::thread_rng();
	let y: f64 = rng.gen(); // generates a float between 0 and 1

	println!("random: {}", y);

	Ok(())
}

#[inline]
fn get_timestamp_rdtscp() -> u64 {
	unsafe {
		let mut _aux = 0;
		let value = arch::__rdtscp(&mut _aux);
		arch::_mm_lfence();
		value
	}
}

pub fn thread_creation() -> Result<(), ()> {
	const N: usize = 1000;

	// cache warmup
	let _ = get_timestamp_rdtscp();

	let start = get_timestamp_rdtscp();
	for _ in 0..N {
		let builder = thread::Builder::new();
		let child = builder.spawn(|| { }).unwrap();
		let _ = child.join();
	}
	let end = get_timestamp_rdtscp();

	println!("Time to create and to join a thread: {} ticks", (end - start) / N as u64);

	Ok(())
}

pub fn bench_sched_one_thread() -> Result<(), ()> {
	let n = 1000000;

	// cache warmup
	thread::yield_now();
	thread::yield_now();
	let _ = get_timestamp_rdtscp();

	let start = get_timestamp_rdtscp();
	for _ in 0..n {
		thread::yield_now();
	}
	let ticks = get_timestamp_rdtscp() - start;

	println!("Scheduling time {} ticks (1 thread)", ticks / n);

	Ok(())
}

pub fn bench_sched_two_threads() -> Result<(), ()> {
	let n = 1000000;
	let nthreads = 2;

	// cache warmup
	thread::yield_now();
	thread::yield_now();
	let _ = get_timestamp_rdtscp();

	let start = get_timestamp_rdtscp();
	let threads: Vec<_> = (0..nthreads - 1)
		.map(|_| {
			thread::spawn(move || {
				for _ in 0..n {
					thread::yield_now();
				}
			})
		})
		.collect();

	for _ in 0..n {
		thread::yield_now();
	}

	let ticks = get_timestamp_rdtscp() - start;

	for t in threads {
		t.join().unwrap();
	}

	println!(
		"Scheduling time {} ticks (2 threads)",
		ticks / (nthreads * n)
	);

	Ok(())
}

pub fn pi_sequential(num_steps: u64) -> Result<(), ()> {
	let step = 1.0 / num_steps as f64;
	let mut sum = 0 as f64;

	for i in 0..num_steps {
		let x = (i as f64 + 0.5) * step;
		sum += 4.0 / (1.0 + x * x);
	}

	let mypi = sum * (1.0 / num_steps as f64);
	println!("Pi: {} (sequential)", mypi);

	if (mypi - PI).abs() < 0.00001 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn pi_parallel(nthreads: u64, num_steps: u64) -> Result<(), ()> {
	let step = 1.0 / num_steps as f64;
	let mut sum = 0.0 as f64;

	let threads: Vec<_> = (0..nthreads)
		.map(|tid| {
			thread::spawn(move || {
				let mut partial_sum = 0 as f64;
				let start = (num_steps / nthreads) * tid;
				let end = (num_steps / nthreads) * (tid + 1);

				for i in start..end {
					let x = (i as f64 + 0.5) * step;
					partial_sum += 4.0 / (1.0 + x * x);
				}

				partial_sum
			})
		})
		.collect();

	for t in threads {
		sum += t.join().unwrap();
	}

	let mypi = sum * (1.0 / num_steps as f64);
	println!("Pi: {} (with {} threads)", mypi, nthreads);

	if (mypi - PI).abs() < 0.00001 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn read_file() -> Result<(), std::io::Error> {
	let mut file = File::open("/etc/hostname")?;
	let mut contents = String::new();
	file.read_to_string(&mut contents)?;

	println!("Hostname: {}", contents);

	Ok(())
}

pub fn create_file() -> Result<(), std::io::Error> {
	{
		let mut file = File::create("/tmp/foo.txt")?;
		file.write_all(b"Hello, world!")?;
	}

	let contents = {
		let mut file = File::open("/tmp/foo.txt")?;
		let mut contents = String::new();
		file.read_to_string(&mut contents)?;
		contents
	};

	// delete temporary file
	std::fs::remove_file("/tmp/foo.txt")?;

	if contents == "Hello, world!" {
		Ok(())
	} else {
		let kind = std::io::ErrorKind::Other;
		Err(std::io::Error::from(kind))
	}
}

pub fn print_argv() -> Result<(), ()> {
	let args = env::args();

	// Prints each argument on a separate line
	for (i, argument) in args.enumerate() {
		println!("argument[{}] = {}", i, argument);
	}

	Ok(())
}

pub fn print_env() -> Result<(), ()> {
	let envs = env::vars();

	// We will iterate through the references to the element returned by
	// env::vars();
	for (key, value) in envs {
		println!("{}: {}", key, value);
	}

	Ok(())
}

pub fn hello() -> Result<(), ()> {
	println!("Hello, world!");

	Ok(())
}

pub fn threading() -> Result<(), ()> {
	// Make a vector to hold the children which are spawned.
	let mut children = vec![];

	for i in 0..2 {
		// Spin up another thread
		children.push(thread::spawn(move || {
			println!("this is thread number {}", i);
		}));
	}

	for child in children {
		// Wait for the thread to finish. Returns a result.
		let _ = child.join();
	}

	Ok(())
}

pub fn laplace(size_x: usize, size_y: usize) -> Result<(), ()> {
	let matrix = matrix_setup(size_x, size_y);

	let now = Instant::now();
	let (iterations, res) = laplace::compute(matrix, size_x, size_y);
	println!(
		"Time to solve {} s, iterations {}, residuum {}",
		now.elapsed().as_secs_f64(),
		iterations,
		res
	);

	if res < 0.01 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn matrix_setup(size_x: usize, size_y: usize) -> vec::Vec<vec::Vec<f64>> {
	let mut matrix = vec![vec![0.0; size_x * size_y]; 2];

	// top row
	for x in 0..size_x {
		matrix[0][x] = 1.0;
		matrix[1][x] = 1.0;
	}

	// bottom row
	for x in 0..size_x {
		matrix[0][(size_y - 1) * size_x + x] = 1.0;
		matrix[1][(size_y - 1) * size_x + x] = 1.0;
	}

	// left row
	for y in 0..size_y {
		matrix[0][y * size_x] = 1.0;
		matrix[1][y * size_x] = 1.0;
	}

	// right row
	for y in 0..size_y {
		matrix[0][y * size_x + size_x - 1] = 1.0;
		matrix[1][y * size_x + size_x - 1] = 1.0;
	}

	matrix
}

fn send_http_rquest() -> Result<Vec<u8>, std::io::Error> {
	let mut stream = TcpStream::connect("10.0.5.1:7878")?;
	let buf =
		b"GET / HTTP/1.1\r\nHost: 10.0.5.1\r\nUser-Agent: hermit/0.3.16\r\nAccept: */*\r\n\r\n";
	stream.write_all(buf)?;

	let mut buf = Vec::new();
	stream.read_to_end(&mut buf)?;

	Ok(buf)
}

pub fn test_http_request() -> Result<(), std::io::Error> {
	let buf = send_http_rquest()?;
	let data = str::from_utf8(&buf).unwrap().to_owned();

	//println!("Receive {}", data);

	match data.starts_with("HTTP/1.1 200 OK") {
		true => println!("Check http response... ok"),
		_ => println!("Check http response... failed!"),
	};

	Ok(())
}
<commit_msg>minor changes to pass the format check<commit_after>use core::arch::x86_64 as arch;
use rand::prelude::*;
use std::env;
use std::f64::consts::PI;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::net::{TcpListener, TcpStream};
use std::str;
use std::thread;
use std::time::Instant;
use std::vec;

mod laplace;
mod matmul;

pub use matmul::test_matmul_strassen;

pub fn random_number() -> Result<(), ()> {
	let mut rng = rand::thread_rng();
	let y: f64 = rng.gen(); // generates a float between 0 and 1

	println!("random: {}", y);

	Ok(())
}

#[inline]
fn get_timestamp_rdtscp() -> u64 {
	unsafe {
		let mut _aux = 0;
		let value = arch::__rdtscp(&mut _aux);
		arch::_mm_lfence();
		value
	}
}

pub fn thread_creation() -> Result<(), ()> {
	const N: usize = 1000;

	// cache warmup
	let _ = get_timestamp_rdtscp();

	let start = get_timestamp_rdtscp();
	for _ in 0..N {
		let builder = thread::Builder::new();
		let child = builder.spawn(|| {}).unwrap();
		let _ = child.join();
	}
	let end = get_timestamp_rdtscp();

	println!(
		"Time to create and to join a thread: {} ticks",
		(end - start) / N as u64
	);

	Ok(())
}

pub fn bench_sched_one_thread() -> Result<(), ()> {
	let n = 1000000;

	// cache warmup
	thread::yield_now();
	thread::yield_now();
	let _ = get_timestamp_rdtscp();

	let start = get_timestamp_rdtscp();
	for _ in 0..n {
		thread::yield_now();
	}
	let ticks = get_timestamp_rdtscp() - start;

	println!("Scheduling time {} ticks (1 thread)", ticks / n);

	Ok(())
}

pub fn bench_sched_two_threads() -> Result<(), ()> {
	let n = 1000000;
	let nthreads = 2;

	// cache warmup
	thread::yield_now();
	thread::yield_now();
	let _ = get_timestamp_rdtscp();

	let start = get_timestamp_rdtscp();
	let threads: Vec<_> = (0..nthreads - 1)
		.map(|_| {
			thread::spawn(move || {
				for _ in 0..n {
					thread::yield_now();
				}
			})
		})
		.collect();

	for _ in 0..n {
		thread::yield_now();
	}

	let ticks = get_timestamp_rdtscp() - start;

	for t in threads {
		t.join().unwrap();
	}

	println!(
		"Scheduling time {} ticks (2 threads)",
		ticks / (nthreads * n)
	);

	Ok(())
}

pub fn pi_sequential(num_steps: u64) -> Result<(), ()> {
	let step = 1.0 / num_steps as f64;
	let mut sum = 0 as f64;

	for i in 0..num_steps {
		let x = (i as f64 + 0.5) * step;
		sum += 4.0 / (1.0 + x * x);
	}

	let mypi = sum * (1.0 / num_steps as f64);
	println!("Pi: {} (sequential)", mypi);

	if (mypi - PI).abs() < 0.00001 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn pi_parallel(nthreads: u64, num_steps: u64) -> Result<(), ()> {
	let step = 1.0 / num_steps as f64;
	let mut sum = 0.0 as f64;

	let threads: Vec<_> = (0..nthreads)
		.map(|tid| {
			thread::spawn(move || {
				let mut partial_sum = 0 as f64;
				let start = (num_steps / nthreads) * tid;
				let end = (num_steps / nthreads) * (tid + 1);

				for i in start..end {
					let x = (i as f64 + 0.5) * step;
					partial_sum += 4.0 / (1.0 + x * x);
				}

				partial_sum
			})
		})
		.collect();

	for t in threads {
		sum += t.join().unwrap();
	}

	let mypi = sum * (1.0 / num_steps as f64);
	println!("Pi: {} (with {} threads)", mypi, nthreads);

	if (mypi - PI).abs() < 0.00001 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn read_file() -> Result<(), std::io::Error> {
	let mut file = File::open("/etc/hostname")?;
	let mut contents = String::new();
	file.read_to_string(&mut contents)?;

	println!("Hostname: {}", contents);

	Ok(())
}

pub fn create_file() -> Result<(), std::io::Error> {
	{
		let mut file = File::create("/tmp/foo.txt")?;
		file.write_all(b"Hello, world!")?;
	}

	let contents = {
		let mut file = File::open("/tmp/foo.txt")?;
		let mut contents = String::new();
		file.read_to_string(&mut contents)?;
		contents
	};

	// delete temporary file
	std::fs::remove_file("/tmp/foo.txt")?;

	if contents == "Hello, world!" {
		Ok(())
	} else {
		let kind = std::io::ErrorKind::Other;
		Err(std::io::Error::from(kind))
	}
}

pub fn print_argv() -> Result<(), ()> {
	let args = env::args();

	// Prints each argument on a separate line
	for (i, argument) in args.enumerate() {
		println!("argument[{}] = {}", i, argument);
	}

	Ok(())
}

pub fn print_env() -> Result<(), ()> {
	let envs = env::vars();

	// We will iterate through the references to the element returned by
	// env::vars();
	for (key, value) in envs {
		println!("{}: {}", key, value);
	}

	Ok(())
}

pub fn hello() -> Result<(), ()> {
	println!("Hello, world!");

	Ok(())
}

pub fn threading() -> Result<(), ()> {
	// Make a vector to hold the children which are spawned.
	let mut children = vec![];

	for i in 0..2 {
		// Spin up another thread
		children.push(thread::spawn(move || {
			println!("this is thread number {}", i);
		}));
	}

	for child in children {
		// Wait for the thread to finish. Returns a result.
		let _ = child.join();
	}

	Ok(())
}

pub fn laplace(size_x: usize, size_y: usize) -> Result<(), ()> {
	let matrix = matrix_setup(size_x, size_y);

	let now = Instant::now();
	let (iterations, res) = laplace::compute(matrix, size_x, size_y);
	println!(
		"Time to solve {} s, iterations {}, residuum {}",
		now.elapsed().as_secs_f64(),
		iterations,
		res
	);

	if res < 0.01 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn matrix_setup(size_x: usize, size_y: usize) -> vec::Vec<vec::Vec<f64>> {
	let mut matrix = vec![vec![0.0; size_x * size_y]; 2];

	// top row
	for x in 0..size_x {
		matrix[0][x] = 1.0;
		matrix[1][x] = 1.0;
	}

	// bottom row
	for x in 0..size_x {
		matrix[0][(size_y - 1) * size_x + x] = 1.0;
		matrix[1][(size_y - 1) * size_x + x] = 1.0;
	}

	// left row
	for y in 0..size_y {
		matrix[0][y * size_x] = 1.0;
		matrix[1][y * size_x] = 1.0;
	}

	// right row
	for y in 0..size_y {
		matrix[0][y * size_x + size_x - 1] = 1.0;
		matrix[1][y * size_x + size_x - 1] = 1.0;
	}

	matrix
}

fn send_http_rquest() -> Result<Vec<u8>, std::io::Error> {
	let mut stream = TcpStream::connect("10.0.5.1:7878")?;
	let buf =
		b"GET / HTTP/1.1\r\nHost: 10.0.5.1\r\nUser-Agent: hermit/0.3.16\r\nAccept: */*\r\n\r\n";
	stream.write_all(buf)?;

	let mut buf = Vec::new();
	stream.read_to_end(&mut buf)?;

	Ok(buf)
}

pub fn test_http_request() -> Result<(), std::io::Error> {
	let buf = send_http_rquest()?;
	let data = str::from_utf8(&buf).unwrap().to_owned();

	//println!("Receive {}", data);

	match data.starts_with("HTTP/1.1 200 OK") {
		true => println!("Check http response... ok"),
		_ => println!("Check http response... failed!"),
	};

	Ok(())
}
<|endoftext|>


<commit_before>use core::arch::x86_64 as arch;
use rand::prelude::*;
use std::env;
use std::f64::consts::PI;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::net::{TcpListener, TcpStream};
use std::str;
use std::thread;
use std::time::Instant;
use std::vec;
#[cfg(target_os = "linux")]
use syscalls::SYS_getpid;

mod laplace;
mod matmul;

pub use matmul::test_matmul_strassen;

pub fn random_number() -> Result<(), ()> {
	let mut rng = rand::thread_rng();
	let y: f64 = rng.gen(); // generates a float between 0 and 1

	println!("random: {}", y);

	Ok(())
}

#[inline]
fn get_timestamp_rdtscp() -> u64 {
	unsafe {
		let mut _aux = 0;
		let value = arch::__rdtscp(&mut _aux);
		arch::_mm_lfence();
		value
	}
}

pub fn thread_creation() -> Result<(), ()> {
	const N: usize = 10;

	// cache warmup
	let _ = get_timestamp_rdtscp();
	{
		let builder = thread::Builder::new();
		let child = builder.spawn(|| {}).unwrap();
		let _ = child.join();
	}

	let start = get_timestamp_rdtscp();
	for _ in 0..N {
		let builder = thread::Builder::new();
		let child = builder.spawn(|| {}).unwrap();
		let _ = child.join();
	}
	let end = get_timestamp_rdtscp();

	println!(
		"Time to create and to join a thread: {} ticks",
		(end - start) / N as u64
	);

	Ok(())
}

extern "C" {
	#[cfg(target_os = "hermit")]
	fn sys_getpid() -> u32;
}

pub fn bench_syscall() -> Result<(), ()> {
	let n = 1000000;

	let ticks = unsafe {
		// cache warmup
		#[cfg(target_os = "hermit")]
		let _ = sys_getpid();
		#[cfg(target_os = "linux")]
		let _ = syscall!(SYS_getpid);
		let _ = get_timestamp_rdtscp();

		let start = get_timestamp_rdtscp();
		for _ in 0..n {
			#[cfg(target_os = "hermit")]
			let _ = sys_getpid();
			#[cfg(target_os = "linux")]
			let _ = syscall!(SYS_getpid);
		}
		get_timestamp_rdtscp() - start
	};

	println!("Time {} for a system call (in ticks)", ticks / n);

	Ok(())
}

pub fn bench_sched_one_thread() -> Result<(), ()> {
	let n = 1000000;

	// cache warmup
	thread::yield_now();
	thread::yield_now();
	let _ = get_timestamp_rdtscp();

	let start = get_timestamp_rdtscp();
	for _ in 0..n {
		thread::yield_now();
	}
	let ticks = get_timestamp_rdtscp() - start;

	println!("Scheduling time {} ticks (1 thread)", ticks / n);

	Ok(())
}

pub fn bench_sched_two_threads() -> Result<(), ()> {
	let n = 1000000;
	let nthreads = 2;

	// cache warmup
	thread::yield_now();
	thread::yield_now();
	let _ = get_timestamp_rdtscp();

	let start = get_timestamp_rdtscp();
	let threads: Vec<_> = (0..nthreads - 1)
		.map(|_| {
			thread::spawn(move || {
				for _ in 0..n {
					thread::yield_now();
				}
			})
		})
		.collect();

	for _ in 0..n {
		thread::yield_now();
	}

	let ticks = get_timestamp_rdtscp() - start;

	for t in threads {
		t.join().unwrap();
	}

	println!(
		"Scheduling time {} ticks (2 threads)",
		ticks / (nthreads * n)
	);

	Ok(())
}

pub fn pi_sequential(num_steps: u64) -> Result<(), ()> {
	let step = 1.0 / num_steps as f64;
	let mut sum = 0 as f64;

	for i in 0..num_steps {
		let x = (i as f64 + 0.5) * step;
		sum += 4.0 / (1.0 + x * x);
	}

	let mypi = sum * (1.0 / num_steps as f64);
	println!("Pi: {} (sequential)", mypi);

	if (mypi - PI).abs() < 0.00001 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn pi_parallel(nthreads: u64, num_steps: u64) -> Result<(), ()> {
	let step = 1.0 / num_steps as f64;
	let mut sum = 0.0 as f64;

	let threads: Vec<_> = (0..nthreads)
		.map(|tid| {
			thread::spawn(move || {
				let mut partial_sum = 0 as f64;
				let start = (num_steps / nthreads) * tid;
				let end = (num_steps / nthreads) * (tid + 1);

				for i in start..end {
					let x = (i as f64 + 0.5) * step;
					partial_sum += 4.0 / (1.0 + x * x);
				}

				partial_sum
			})
		})
		.collect();

	for t in threads {
		sum += t.join().unwrap();
	}

	let mypi = sum * (1.0 / num_steps as f64);
	println!("Pi: {} (with {} threads)", mypi, nthreads);

	if (mypi - PI).abs() < 0.00001 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn read_file() -> Result<(), std::io::Error> {
	let mut file = File::open("/etc/hostname")?;
	let mut contents = String::new();
	file.read_to_string(&mut contents)?;

	println!("Hostname: {}", contents);

	Ok(())
}

pub fn create_file() -> Result<(), std::io::Error> {
	{
		let mut file = File::create("/tmp/foo.txt")?;
		file.write_all(b"Hello, world!")?;
	}

	let contents = {
		let mut file = File::open("/tmp/foo.txt")?;
		let mut contents = String::new();
		file.read_to_string(&mut contents)?;
		contents
	};

	// delete temporary file
	std::fs::remove_file("/tmp/foo.txt")?;

	if contents == "Hello, world!" {
		Ok(())
	} else {
		let kind = std::io::ErrorKind::Other;
		Err(std::io::Error::from(kind))
	}
}

pub fn print_argv() -> Result<(), ()> {
	let args = env::args();

	// Prints each argument on a separate line
	for (i, argument) in args.enumerate() {
		println!("argument[{}] = {}", i, argument);
	}

	Ok(())
}

pub fn print_env() -> Result<(), ()> {
	let envs = env::vars();

	// We will iterate through the references to the element returned by
	// env::vars();
	for (key, value) in envs {
		println!("{}: {}", key, value);
	}

	Ok(())
}

pub fn hello() -> Result<(), ()> {
	println!("Hello, world!");

	Ok(())
}

pub fn threading() -> Result<(), ()> {
	// Make a vector to hold the children which are spawned.
	let mut children = vec![];

	for i in 0..2 {
		// Spin up another thread
		children.push(thread::spawn(move || {
			println!("this is thread number {}", i);
		}));
	}

	for child in children {
		// Wait for the thread to finish. Returns a result.
		let _ = child.join();
	}

	Ok(())
}

pub fn laplace(size_x: usize, size_y: usize) -> Result<(), ()> {
	let matrix = matrix_setup(size_x, size_y);

	let now = Instant::now();
	let (iterations, res) = laplace::compute(matrix, size_x, size_y);
	println!(
		"Time to solve {} s, iterations {}, residuum {}",
		now.elapsed().as_secs_f64(),
		iterations,
		res
	);

	if res < 0.01 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn matrix_setup(size_x: usize, size_y: usize) -> vec::Vec<vec::Vec<f64>> {
	let mut matrix = vec![vec![0.0; size_x * size_y]; 2];

	// top row
	for x in 0..size_x {
		matrix[0][x] = 1.0;
		matrix[1][x] = 1.0;
	}

	// bottom row
	for x in 0..size_x {
		matrix[0][(size_y - 1) * size_x + x] = 1.0;
		matrix[1][(size_y - 1) * size_x + x] = 1.0;
	}

	// left row
	for y in 0..size_y {
		matrix[0][y * size_x] = 1.0;
		matrix[1][y * size_x] = 1.0;
	}

	// right row
	for y in 0..size_y {
		matrix[0][y * size_x + size_x - 1] = 1.0;
		matrix[1][y * size_x + size_x - 1] = 1.0;
	}

	matrix
}

fn send_http_rquest() -> Result<Vec<u8>, std::io::Error> {
	let mut stream = TcpStream::connect("10.0.5.1:7878")?;
	let buf =
		b"GET / HTTP/1.1\r\nHost: 10.0.5.1\r\nUser-Agent: hermit/0.3.16\r\nAccept: */*\r\n\r\n";
	stream.write_all(buf)?;

	let mut buf = Vec::new();
	stream.read_to_end(&mut buf)?;

	Ok(buf)
}

pub fn test_http_request() -> Result<(), std::io::Error> {
	let buf = send_http_rquest()?;
	let data = str::from_utf8(&buf).unwrap().to_owned();

	//println!("Receive {}", data);

	match data.starts_with("HTTP/1.1 200 OK") {
		true => println!("Check http response... ok"),
		_ => println!("Check http response... failed!"),
	};

	Ok(())
}
<commit_msg>Demo: Add UTF-8 examples to hello test (#31)<commit_after>use core::arch::x86_64 as arch;
use rand::prelude::*;
use std::env;
use std::f64::consts::PI;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::net::{TcpListener, TcpStream};
use std::str;
use std::thread;
use std::time::Instant;
use std::vec;
#[cfg(target_os = "linux")]
use syscalls::SYS_getpid;

mod laplace;
mod matmul;

pub use matmul::test_matmul_strassen;

pub fn random_number() -> Result<(), ()> {
	let mut rng = rand::thread_rng();
	let y: f64 = rng.gen(); // generates a float between 0 and 1

	println!("random: {}", y);

	Ok(())
}

#[inline]
fn get_timestamp_rdtscp() -> u64 {
	unsafe {
		let mut _aux = 0;
		let value = arch::__rdtscp(&mut _aux);
		arch::_mm_lfence();
		value
	}
}

pub fn thread_creation() -> Result<(), ()> {
	const N: usize = 10;

	// cache warmup
	let _ = get_timestamp_rdtscp();
	{
		let builder = thread::Builder::new();
		let child = builder.spawn(|| {}).unwrap();
		let _ = child.join();
	}

	let start = get_timestamp_rdtscp();
	for _ in 0..N {
		let builder = thread::Builder::new();
		let child = builder.spawn(|| {}).unwrap();
		let _ = child.join();
	}
	let end = get_timestamp_rdtscp();

	println!(
		"Time to create and to join a thread: {} ticks",
		(end - start) / N as u64
	);

	Ok(())
}

extern "C" {
	#[cfg(target_os = "hermit")]
	fn sys_getpid() -> u32;
}

pub fn bench_syscall() -> Result<(), ()> {
	let n = 1000000;

	let ticks = unsafe {
		// cache warmup
		#[cfg(target_os = "hermit")]
		let _ = sys_getpid();
		#[cfg(target_os = "linux")]
		let _ = syscall!(SYS_getpid);
		let _ = get_timestamp_rdtscp();

		let start = get_timestamp_rdtscp();
		for _ in 0..n {
			#[cfg(target_os = "hermit")]
			let _ = sys_getpid();
			#[cfg(target_os = "linux")]
			let _ = syscall!(SYS_getpid);
		}
		get_timestamp_rdtscp() - start
	};

	println!("Time {} for a system call (in ticks)", ticks / n);

	Ok(())
}

pub fn bench_sched_one_thread() -> Result<(), ()> {
	let n = 1000000;

	// cache warmup
	thread::yield_now();
	thread::yield_now();
	let _ = get_timestamp_rdtscp();

	let start = get_timestamp_rdtscp();
	for _ in 0..n {
		thread::yield_now();
	}
	let ticks = get_timestamp_rdtscp() - start;

	println!("Scheduling time {} ticks (1 thread)", ticks / n);

	Ok(())
}

pub fn bench_sched_two_threads() -> Result<(), ()> {
	let n = 1000000;
	let nthreads = 2;

	// cache warmup
	thread::yield_now();
	thread::yield_now();
	let _ = get_timestamp_rdtscp();

	let start = get_timestamp_rdtscp();
	let threads: Vec<_> = (0..nthreads - 1)
		.map(|_| {
			thread::spawn(move || {
				for _ in 0..n {
					thread::yield_now();
				}
			})
		})
		.collect();

	for _ in 0..n {
		thread::yield_now();
	}

	let ticks = get_timestamp_rdtscp() - start;

	for t in threads {
		t.join().unwrap();
	}

	println!(
		"Scheduling time {} ticks (2 threads)",
		ticks / (nthreads * n)
	);

	Ok(())
}

pub fn pi_sequential(num_steps: u64) -> Result<(), ()> {
	let step = 1.0 / num_steps as f64;
	let mut sum = 0 as f64;

	for i in 0..num_steps {
		let x = (i as f64 + 0.5) * step;
		sum += 4.0 / (1.0 + x * x);
	}

	let mypi = sum * (1.0 / num_steps as f64);
	println!("Pi: {} (sequential)", mypi);

	if (mypi - PI).abs() < 0.00001 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn pi_parallel(nthreads: u64, num_steps: u64) -> Result<(), ()> {
	let step = 1.0 / num_steps as f64;
	let mut sum = 0.0 as f64;

	let threads: Vec<_> = (0..nthreads)
		.map(|tid| {
			thread::spawn(move || {
				let mut partial_sum = 0 as f64;
				let start = (num_steps / nthreads) * tid;
				let end = (num_steps / nthreads) * (tid + 1);

				for i in start..end {
					let x = (i as f64 + 0.5) * step;
					partial_sum += 4.0 / (1.0 + x * x);
				}

				partial_sum
			})
		})
		.collect();

	for t in threads {
		sum += t.join().unwrap();
	}

	let mypi = sum * (1.0 / num_steps as f64);
	println!("Pi: {} (with {} threads)", mypi, nthreads);

	if (mypi - PI).abs() < 0.00001 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn read_file() -> Result<(), std::io::Error> {
	let mut file = File::open("/etc/hostname")?;
	let mut contents = String::new();
	file.read_to_string(&mut contents)?;

	println!("Hostname: {}", contents);

	Ok(())
}

pub fn create_file() -> Result<(), std::io::Error> {
	{
		let mut file = File::create("/tmp/foo.txt")?;
		file.write_all(b"Hello, world!")?;
	}

	let contents = {
		let mut file = File::open("/tmp/foo.txt")?;
		let mut contents = String::new();
		file.read_to_string(&mut contents)?;
		contents
	};

	// delete temporary file
	std::fs::remove_file("/tmp/foo.txt")?;

	if contents == "Hello, world!" {
		Ok(())
	} else {
		let kind = std::io::ErrorKind::Other;
		Err(std::io::Error::from(kind))
	}
}

pub fn print_argv() -> Result<(), ()> {
	let args = env::args();

	// Prints each argument on a separate line
	for (i, argument) in args.enumerate() {
		println!("argument[{}] = {}", i, argument);
	}

	Ok(())
}

pub fn print_env() -> Result<(), ()> {
	let envs = env::vars();

	// We will iterate through the references to the element returned by
	// env::vars();
	for (key, value) in envs {
		println!("{}: {}", key, value);
	}

	Ok(())
}

pub fn hello() -> Result<(), ()> {
	println!("Hello, world!");
	println!("Привет мир!");
	println!("こんにちは世界");
	println!("你好，世界");
	println!("สวัสดีชาวโลก");
	println!("Chào thế giới");
	let crab = vec![0xF0 as u8, 0x9F as u8, 0xA6 as u8, 0x80 as u8];
	println!(
		"Crab emoji: {}",
		String::from_utf8(crab).unwrap_or_default()
	);
	Ok(())
}

pub fn threading() -> Result<(), ()> {
	// Make a vector to hold the children which are spawned.
	let mut children = vec![];

	for i in 0..2 {
		// Spin up another thread
		children.push(thread::spawn(move || {
			println!("this is thread number {}", i);
		}));
	}

	for child in children {
		// Wait for the thread to finish. Returns a result.
		let _ = child.join();
	}

	Ok(())
}

pub fn laplace(size_x: usize, size_y: usize) -> Result<(), ()> {
	let matrix = matrix_setup(size_x, size_y);

	let now = Instant::now();
	let (iterations, res) = laplace::compute(matrix, size_x, size_y);
	println!(
		"Time to solve {} s, iterations {}, residuum {}",
		now.elapsed().as_secs_f64(),
		iterations,
		res
	);

	if res < 0.01 {
		Ok(())
	} else {
		Err(())
	}
}

pub fn matrix_setup(size_x: usize, size_y: usize) -> vec::Vec<vec::Vec<f64>> {
	let mut matrix = vec![vec![0.0; size_x * size_y]; 2];

	// top row
	for x in 0..size_x {
		matrix[0][x] = 1.0;
		matrix[1][x] = 1.0;
	}

	// bottom row
	for x in 0..size_x {
		matrix[0][(size_y - 1) * size_x + x] = 1.0;
		matrix[1][(size_y - 1) * size_x + x] = 1.0;
	}

	// left row
	for y in 0..size_y {
		matrix[0][y * size_x] = 1.0;
		matrix[1][y * size_x] = 1.0;
	}

	// right row
	for y in 0..size_y {
		matrix[0][y * size_x + size_x - 1] = 1.0;
		matrix[1][y * size_x + size_x - 1] = 1.0;
	}

	matrix
}

fn send_http_rquest() -> Result<Vec<u8>, std::io::Error> {
	let mut stream = TcpStream::connect("10.0.5.1:7878")?;
	let buf =
		b"GET / HTTP/1.1\r\nHost: 10.0.5.1\r\nUser-Agent: hermit/0.3.16\r\nAccept: */*\r\n\r\n";
	stream.write_all(buf)?;

	let mut buf = Vec::new();
	stream.read_to_end(&mut buf)?;

	Ok(buf)
}

pub fn test_http_request() -> Result<(), std::io::Error> {
	let buf = send_http_rquest()?;
	let data = str::from_utf8(&buf).unwrap().to_owned();

	//println!("Receive {}", data);

	match data.starts_with("HTTP/1.1 200 OK") {
		true => println!("Check http response... ok"),
		_ => println!("Check http response... failed!"),
	};

	Ok(())
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests;

pub mod response;

pub use client::response::*;
use std::io::Read;
use message::Message;
use hyper::client::Client as HttpClient;
use hyper::header::{Authorization, ContentType, Connection};
use hyper::status::StatusCode;
use rustc_serialize::json::{self, ToJson};

pub struct Client {
    http_client: HttpClient,
}

impl Client {
    /// Get a new instance of Client.
    pub fn new() -> Client {
        Client {
            http_client: HttpClient::new(),
        }
    }

    /// Send a message using your FCM API Key.
    /// # Examples:
    /// ```no_run
    /// use fcm::{MessageBuilder, Client};
    /// use std::collections::HashMap;
    ///
    /// let mut map = HashMap::new();
    /// map.insert("message", "Howdy!");
    ///
    /// let message = MessageBuilder::new("<registration id>").data(map).finalize();
    /// let client = Client::new();
    /// let result = client.send(message, "<FCM API Key>");
    /// ```
    pub fn send(&self, message: Message, api_key: &str) -> Result<FcmResponse, FcmError> {
        let payload = message.to_json().to_string();
        let auth_header = format!("key={}", api_key);

        let response = self.http_client.
            post("https://fcm.googleapis.com/fcm/send").
            header(Connection::keep_alive()).
            header(ContentType::json()).
            body(&payload).
            header(Authorization(auth_header)).
            header(ContentType::json()).
            send();

        match response {
            Ok(mut response) => {
                let mut body = String::new();
                response.read_to_string(&mut body).unwrap();

                Client::parse_response(response.status, &body)
            },
            Err(_) => {
                Client::parse_response(StatusCode::InternalServerError, "Server Error")
            }
        }
    }

    fn parse_response(status: StatusCode, body: &str) -> Result<response::FcmResponse, response::FcmError> {
        use hyper::status::StatusCode::*;
        match status {
            Ok =>
                Result::Ok(json::decode(body).unwrap()),
            Unauthorized =>
                Err(response::FcmError::Unauthorized),
            BadRequest =>
                Err(response::FcmError::InvalidMessage(body.to_string())),
            status if status.is_server_error() =>
                Err(response::FcmError::ServerError),
            _ =>
                Err(response::FcmError::InvalidMessage("Unknown Error".to_string())),
        }
    }
}
<commit_msg>Add possibility to change default fcm uri<commit_after>#[cfg(test)]
mod tests;

pub mod response;

pub use client::response::*;
use std::io::Read;
use message::Message;
use hyper::client::Client as HttpClient;
use hyper::header::{Authorization, ContentType, Connection};
use hyper::status::StatusCode;
use rustc_serialize::json::{self, ToJson};

pub struct Client<'a> {
    http_client: HttpClient,
    fcm_uri: &'a str,
}

impl<'a> Client<'a> {
    /// Get a new instance of Client.
    pub fn new() -> Client<'a> {
        Client {
            http_client: HttpClient::new(),
            fcm_uri: "https://fcm.googleapis.com/fcm/send",
        }
    }

    /// Send a message using your FCM API Key.
    /// # Examples:
    /// ```no_run
    /// use fcm::{MessageBuilder, Client};
    /// use std::collections::HashMap;
    ///
    /// let mut map = HashMap::new();
    /// map.insert("message", "Howdy!");
    ///
    /// let message = MessageBuilder::new("<registration id>").data(map).finalize();
    /// let client = Client::new();
    /// let result = client.send(message, "<FCM API Key>");
    /// ```
    pub fn send(&self, message: Message, api_key: &str) -> Result<FcmResponse, FcmError> {
        let payload = message.to_json().to_string();
        let auth_header = format!("key={}", api_key);

        let response = self.http_client.
            post(self.fcm_uri).
            header(Connection::keep_alive()).
            header(ContentType::json()).
            body(&payload).
            header(Authorization(auth_header)).
            header(ContentType::json()).
            send();

        match response {
            Ok(mut response) => {
                let mut body = String::new();
                response.read_to_string(&mut body).unwrap();

                Client::parse_response(response.status, &body)
            },
            Err(_) => {
                Client::parse_response(StatusCode::InternalServerError, "Server Error")
            }
        }
    }

    /// Set fcm uri if need to connect to other uri than default.
    pub fn fcm_uri(&mut self, fcm_uri: &'a str) -> &mut Client<'a> {
        self.fcm_uri = fcm_uri;
        self
    }

    fn parse_response(status: StatusCode, body: &str) -> Result<response::FcmResponse, response::FcmError> {
        use hyper::status::StatusCode::*;
        match status {
            Ok =>
                Result::Ok(json::decode(body).unwrap()),
            Unauthorized =>
                Err(response::FcmError::Unauthorized),
            BadRequest =>
                Err(response::FcmError::InvalidMessage(body.to_string())),
            status if status.is_server_error() =>
                Err(response::FcmError::ServerError),
            _ =>
                Err(response::FcmError::InvalidMessage("Unknown Error".to_string())),
        }
    }
}
<|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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Keyword, Method, PHYSICAL_SIDES, ALL_SIDES, maybe_moz_logical_alias %>

<% data.new_style_struct("Border", inherited=False,
                   additional_methods=[Method("border_" + side + "_has_nonzero_width",
                                              "bool") for side in ["top", "right", "bottom", "left"]]) %>
<%
    def maybe_logical_spec(side, kind):
        if side[1]: # if it is logical
            return "https://drafts.csswg.org/css-logical-props/#propdef-border-%s-%s" % (side[0], kind)
        else:
            return "https://drafts.csswg.org/css-backgrounds/#border-%s-%s" % (side[0], kind)
%>
% for side in ALL_SIDES:
    ${helpers.predefined_type("border-%s-color" % side[0], "Color",
                              "computed_value::T::currentcolor()",
                              alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-color"),
                              spec=maybe_logical_spec(side, "color"),
                              animation_value_type="IntermediateColor",
                              logical=side[1],
                              allow_quirks=not side[1],
                              ignored_when_colors_disabled=True)}

    ${helpers.predefined_type("border-%s-style" % side[0], "BorderStyle",
                              "specified::BorderStyle::none",
                              need_clone=True,
                              alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
                              spec=maybe_logical_spec(side, "style"),
                              animation_value_type="none", logical=side[1])}

    ${helpers.predefined_type("border-%s-width" % side[0],
                              "BorderSideWidth",
                              "Au::from_px(3)",
                              computed_type="::app_units::Au",
                              alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"),
                              spec=maybe_logical_spec(side, "width"),
                              animation_value_type="ComputedValue",
                              logical=side[1],
                              allow_quirks=not side[1])}
% endfor

${helpers.gecko_keyword_conversion(Keyword('border-style',
                                   "none solid double dotted dashed hidden groove ridge inset outset"),
                                   type="::values::specified::BorderStyle")}

// FIXME(#4126): when gfx supports painting it, make this Size2D<LengthOrPercentage>
% for corner in ["top-left", "top-right", "bottom-right", "bottom-left"]:
    ${helpers.predefined_type("border-" + corner + "-radius", "BorderCornerRadius",
                              "computed::LengthOrPercentage::zero().into()",
                              "parse", extra_prefixes="webkit",
                              spec="https://drafts.csswg.org/css-backgrounds/#border-%s-radius" % corner,
                              boxed=True,
                              animation_value_type="ComputedValue")}
% endfor

/// -moz-border-*-colors: color, string, enum, none, inherit/initial
/// These non-spec properties are just for Gecko (Stylo) internal use.
% for side in PHYSICAL_SIDES:
    <%helpers:longhand name="-moz-border-${side}-colors" animation_value_type="discrete"
                       spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-border-*-colors)"
                       products="gecko"
                       ignored_when_colors_disabled="True">
        use std::fmt;
        use style_traits::ToCss;
        use values::specified::RGBAColor;
        no_viewport_percentage!(SpecifiedValue);

        pub mod computed_value {
            use cssparser::RGBA;
            #[derive(Debug, Clone, PartialEq)]
            #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
            pub struct T(pub Option<Vec<RGBA>>);
        }

        #[derive(Debug, Clone, PartialEq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum SpecifiedValue {
            None,
            Colors(Vec<RGBAColor>),
        }

        impl ToCss for computed_value::T {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                match self.0 {
                    None => return dest.write_str("none"),
                    Some(ref vec) => {
                        let mut first = true;
                        for ref color in vec {
                            if !first {
                                dest.write_str(" ")?;
                            }
                            first = false;
                            color.to_css(dest)?
                        }
                        Ok(())
                    }
                }
            }
        }

        impl ToCss for SpecifiedValue {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                match *self {
                    SpecifiedValue::None => return dest.write_str("none"),
                    SpecifiedValue::Colors(ref vec) => {
                        let mut first = true;
                        for ref color in vec {
                            if !first {
                                dest.write_str(" ")?;
                            }
                            first = false;
                            color.to_css(dest)?
                        }
                        Ok(())
                    }
                }
            }
        }

        #[inline] pub fn get_initial_value() -> computed_value::T {
            computed_value::T(None)
        }

        #[inline] pub fn get_initial_specified_value() -> SpecifiedValue {
            SpecifiedValue::None
        }

        impl ToComputedValue for SpecifiedValue {
            type ComputedValue = computed_value::T;

            #[inline]
            fn to_computed_value(&self, context: &Context) -> computed_value::T {
                match *self {
                    SpecifiedValue::Colors(ref vec) => {
                        computed_value::T(Some(vec.iter()
                                                  .map(|c| c.to_computed_value(context))
                                                  .collect()))
                    },
                    SpecifiedValue::None => {
                        computed_value::T(None)
                    }
                }
            }
            #[inline]
            fn from_computed_value(computed: &computed_value::T) -> Self {
                match *computed {
                    computed_value::T(Some(ref vec)) => {
                        SpecifiedValue::Colors(vec.iter()
                                                  .map(ToComputedValue::from_computed_value)
                                                  .collect())
                    },
                    computed_value::T(None) => {
                        SpecifiedValue::None
                    }
                }
            }
        }

        #[inline]
        pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                             -> Result<SpecifiedValue, ParseError<'i>> {
            if input.try(|input| input.expect_ident_matching("none")).is_ok() {
                return Ok(SpecifiedValue::None)
            }

            let mut result = Vec::new();
            while let Ok(value) = input.try(|i| RGBAColor::parse(context, i)) {
                result.push(value);
            }

            if !result.is_empty() {
                Ok(SpecifiedValue::Colors(result))
            } else {
                Err(StyleParseError::UnspecifiedError.into())
            }
        }
    </%helpers:longhand>
% endfor

${helpers.single_keyword("box-decoration-break", "slice clone",
                         gecko_enum_prefix="StyleBoxDecorationBreak",
                         gecko_inexhaustive=True,
                         spec="https://drafts.csswg.org/css-break/#propdef-box-decoration-break",
                         products="gecko", animation_value_type="discrete")}

${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
                         gecko_ffi_name="mFloatEdge",
                         gecko_enum_prefix="StyleFloatEdge",
                         gecko_inexhaustive=True,
                         products="gecko",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
                         animation_value_type="discrete")}

${helpers.predefined_type("border-image-source", "ImageLayer",
    initial_value="Either::First(None_)",
    initial_specified_value="Either::First(None_)",
    spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
    vector=False,
    animation_value_type="discrete",
    has_uncacheable_values=False,
    boxed="True")}

${helpers.predefined_type("border-image-outset", "LengthOrNumberRect",
    parse_method="parse_non_negative",
    initial_value="computed::LengthOrNumber::zero().into()",
    initial_specified_value="specified::LengthOrNumber::zero().into()",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
    animation_value_type="discrete",
    boxed=True)}

<%helpers:longhand name="border-image-repeat" animation_value_type="discrete"
                   spec="https://drafts.csswg.org/css-backgrounds/#border-image-repeat">
    use style_traits::ToCss;

    no_viewport_percentage!(SpecifiedValue);

    pub mod computed_value {
        pub use super::RepeatKeyword;

        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        #[derive(Debug, Clone, PartialEq, ToCss)]
        pub struct T(pub RepeatKeyword, pub RepeatKeyword);
    }

    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    #[derive(Debug, Clone, PartialEq, ToCss)]
    pub struct SpecifiedValue(pub RepeatKeyword,
                              pub Option<RepeatKeyword>);

    define_css_keyword_enum!(RepeatKeyword:
                             "stretch" => Stretch,
                             "repeat" => Repeat,
                             "round" => Round,
                             "space" => Space);

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T(RepeatKeyword::Stretch, RepeatKeyword::Stretch)
    }

    #[inline]
    pub fn get_initial_specified_value() -> SpecifiedValue {
        SpecifiedValue(RepeatKeyword::Stretch, None)
    }

    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, _context: &Context) -> computed_value::T {
            computed_value::T(self.0, self.1.unwrap_or(self.0))
        }
        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            SpecifiedValue(computed.0, Some(computed.1))
        }
    }

    pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                         -> Result<SpecifiedValue, ParseError<'i>> {
        let first = RepeatKeyword::parse(input)?;
        let second = input.try(RepeatKeyword::parse).ok();

        Ok(SpecifiedValue(first, second))
    }
</%helpers:longhand>

${helpers.predefined_type("border-image-width", "BorderImageWidth",
    initial_value="computed::BorderImageSideWidth::one().into()",
    initial_specified_value="specified::BorderImageSideWidth::one().into()",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
    animation_value_type="discrete",
    boxed=True)}

${helpers.predefined_type("border-image-slice", "BorderImageSlice",
    initial_value="computed::NumberOrPercentage::Percentage(computed::Percentage(1.)).into()",
    initial_specified_value="specified::NumberOrPercentage::Percentage(specified::Percentage::new(1.)).into()",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
    animation_value_type="discrete",
    boxed=True)}

#[cfg(feature = "gecko")]
impl ::values::computed::BorderImageWidth {
    pub fn to_gecko_rect(&self, sides: &mut ::gecko_bindings::structs::nsStyleSides) {
        use gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue};
        use gecko::values::GeckoStyleCoordConvertible;
        use values::generics::border::BorderImageSideWidth;

        % for i in range(0, 4):
        match self.${i} {
            BorderImageSideWidth::Auto => {
                sides.data_at_mut(${i}).set_value(CoordDataValue::Auto)
            },
            BorderImageSideWidth::Length(l) => {
                l.to_gecko_style_coord(&mut sides.data_at_mut(${i}))
            },
            BorderImageSideWidth::Number(n) => {
                sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n))
            },
        }
        % endfor
    }

    pub fn from_gecko_rect(sides: &::gecko_bindings::structs::nsStyleSides)
                           -> Option<::values::computed::BorderImageWidth> {
        use gecko_bindings::structs::nsStyleUnit::{eStyleUnit_Factor, eStyleUnit_Auto};
        use gecko_bindings::sugar::ns_style_coord::CoordData;
        use gecko::values::GeckoStyleCoordConvertible;
        use values::computed::{LengthOrPercentage, Number};
        use values::generics::border::BorderImageSideWidth;

        Some(
            ::values::computed::BorderImageWidth::new(
                % for i in range(0, 4):
                match sides.data_at(${i}).unit() {
                    eStyleUnit_Auto => {
                        BorderImageSideWidth::Auto
                    },
                    eStyleUnit_Factor => {
                        BorderImageSideWidth::Number(
                            Number::from_gecko_style_coord(&sides.data_at(${i}))
                                .expect("sides[${i}] could not convert to Number"))
                    },
                    _ => {
                        BorderImageSideWidth::Length(
                            LengthOrPercentage::from_gecko_style_coord(&sides.data_at(${i}))
                                .expect("sides[${i}] could not convert to LengthOrPercentager"))
                    },
                },
                % endfor
            )
        )
    }
}
<commit_msg>make border-XX-style animatable<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Keyword, Method, PHYSICAL_SIDES, ALL_SIDES, maybe_moz_logical_alias %>

<% data.new_style_struct("Border", inherited=False,
                   additional_methods=[Method("border_" + side + "_has_nonzero_width",
                                              "bool") for side in ["top", "right", "bottom", "left"]]) %>
<%
    def maybe_logical_spec(side, kind):
        if side[1]: # if it is logical
            return "https://drafts.csswg.org/css-logical-props/#propdef-border-%s-%s" % (side[0], kind)
        else:
            return "https://drafts.csswg.org/css-backgrounds/#border-%s-%s" % (side[0], kind)
%>
% for side in ALL_SIDES:
    <%
        side_name = side[0]
        is_logical = side[1]
    %>
    ${helpers.predefined_type("border-%s-color" % side_name, "Color",
                              "computed_value::T::currentcolor()",
                              alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-color"),
                              spec=maybe_logical_spec(side, "color"),
                              animation_value_type="IntermediateColor",
                              logical=is_logical,
                              allow_quirks=not is_logical,
                              ignored_when_colors_disabled=True)}

    ${helpers.predefined_type("border-%s-style" % side_name, "BorderStyle",
                              "specified::BorderStyle::none",
                              alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
                              spec=maybe_logical_spec(side, "style"),
                              animation_value_type="discrete" if not is_logical else "none",
                              logical=is_logical)}

    ${helpers.predefined_type("border-%s-width" % side_name,
                              "BorderSideWidth",
                              "Au::from_px(3)",
                              computed_type="::app_units::Au",
                              alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"),
                              spec=maybe_logical_spec(side, "width"),
                              animation_value_type="ComputedValue",
                              logical=is_logical,
                              allow_quirks=not is_logical)}
% endfor

${helpers.gecko_keyword_conversion(Keyword('border-style',
                                   "none solid double dotted dashed hidden groove ridge inset outset"),
                                   type="::values::specified::BorderStyle")}

// FIXME(#4126): when gfx supports painting it, make this Size2D<LengthOrPercentage>
% for corner in ["top-left", "top-right", "bottom-right", "bottom-left"]:
    ${helpers.predefined_type("border-" + corner + "-radius", "BorderCornerRadius",
                              "computed::LengthOrPercentage::zero().into()",
                              "parse", extra_prefixes="webkit",
                              spec="https://drafts.csswg.org/css-backgrounds/#border-%s-radius" % corner,
                              boxed=True,
                              animation_value_type="ComputedValue")}
% endfor

/// -moz-border-*-colors: color, string, enum, none, inherit/initial
/// These non-spec properties are just for Gecko (Stylo) internal use.
% for side in PHYSICAL_SIDES:
    <%helpers:longhand name="-moz-border-${side}-colors" animation_value_type="discrete"
                       spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-border-*-colors)"
                       products="gecko"
                       ignored_when_colors_disabled="True">
        use std::fmt;
        use style_traits::ToCss;
        use values::specified::RGBAColor;
        no_viewport_percentage!(SpecifiedValue);

        pub mod computed_value {
            use cssparser::RGBA;
            #[derive(Debug, Clone, PartialEq)]
            #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
            pub struct T(pub Option<Vec<RGBA>>);
        }

        #[derive(Debug, Clone, PartialEq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum SpecifiedValue {
            None,
            Colors(Vec<RGBAColor>),
        }

        impl ToCss for computed_value::T {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                match self.0 {
                    None => return dest.write_str("none"),
                    Some(ref vec) => {
                        let mut first = true;
                        for ref color in vec {
                            if !first {
                                dest.write_str(" ")?;
                            }
                            first = false;
                            color.to_css(dest)?
                        }
                        Ok(())
                    }
                }
            }
        }

        impl ToCss for SpecifiedValue {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                match *self {
                    SpecifiedValue::None => return dest.write_str("none"),
                    SpecifiedValue::Colors(ref vec) => {
                        let mut first = true;
                        for ref color in vec {
                            if !first {
                                dest.write_str(" ")?;
                            }
                            first = false;
                            color.to_css(dest)?
                        }
                        Ok(())
                    }
                }
            }
        }

        #[inline] pub fn get_initial_value() -> computed_value::T {
            computed_value::T(None)
        }

        #[inline] pub fn get_initial_specified_value() -> SpecifiedValue {
            SpecifiedValue::None
        }

        impl ToComputedValue for SpecifiedValue {
            type ComputedValue = computed_value::T;

            #[inline]
            fn to_computed_value(&self, context: &Context) -> computed_value::T {
                match *self {
                    SpecifiedValue::Colors(ref vec) => {
                        computed_value::T(Some(vec.iter()
                                                  .map(|c| c.to_computed_value(context))
                                                  .collect()))
                    },
                    SpecifiedValue::None => {
                        computed_value::T(None)
                    }
                }
            }
            #[inline]
            fn from_computed_value(computed: &computed_value::T) -> Self {
                match *computed {
                    computed_value::T(Some(ref vec)) => {
                        SpecifiedValue::Colors(vec.iter()
                                                  .map(ToComputedValue::from_computed_value)
                                                  .collect())
                    },
                    computed_value::T(None) => {
                        SpecifiedValue::None
                    }
                }
            }
        }

        #[inline]
        pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                             -> Result<SpecifiedValue, ParseError<'i>> {
            if input.try(|input| input.expect_ident_matching("none")).is_ok() {
                return Ok(SpecifiedValue::None)
            }

            let mut result = Vec::new();
            while let Ok(value) = input.try(|i| RGBAColor::parse(context, i)) {
                result.push(value);
            }

            if !result.is_empty() {
                Ok(SpecifiedValue::Colors(result))
            } else {
                Err(StyleParseError::UnspecifiedError.into())
            }
        }
    </%helpers:longhand>
% endfor

${helpers.single_keyword("box-decoration-break", "slice clone",
                         gecko_enum_prefix="StyleBoxDecorationBreak",
                         gecko_inexhaustive=True,
                         spec="https://drafts.csswg.org/css-break/#propdef-box-decoration-break",
                         products="gecko", animation_value_type="discrete")}

${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
                         gecko_ffi_name="mFloatEdge",
                         gecko_enum_prefix="StyleFloatEdge",
                         gecko_inexhaustive=True,
                         products="gecko",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
                         animation_value_type="discrete")}

${helpers.predefined_type("border-image-source", "ImageLayer",
    initial_value="Either::First(None_)",
    initial_specified_value="Either::First(None_)",
    spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
    vector=False,
    animation_value_type="discrete",
    has_uncacheable_values=False,
    boxed="True")}

${helpers.predefined_type("border-image-outset", "LengthOrNumberRect",
    parse_method="parse_non_negative",
    initial_value="computed::LengthOrNumber::zero().into()",
    initial_specified_value="specified::LengthOrNumber::zero().into()",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
    animation_value_type="discrete",
    boxed=True)}

<%helpers:longhand name="border-image-repeat" animation_value_type="discrete"
                   spec="https://drafts.csswg.org/css-backgrounds/#border-image-repeat">
    use style_traits::ToCss;

    no_viewport_percentage!(SpecifiedValue);

    pub mod computed_value {
        pub use super::RepeatKeyword;

        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        #[derive(Debug, Clone, PartialEq, ToCss)]
        pub struct T(pub RepeatKeyword, pub RepeatKeyword);
    }

    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    #[derive(Debug, Clone, PartialEq, ToCss)]
    pub struct SpecifiedValue(pub RepeatKeyword,
                              pub Option<RepeatKeyword>);

    define_css_keyword_enum!(RepeatKeyword:
                             "stretch" => Stretch,
                             "repeat" => Repeat,
                             "round" => Round,
                             "space" => Space);

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T(RepeatKeyword::Stretch, RepeatKeyword::Stretch)
    }

    #[inline]
    pub fn get_initial_specified_value() -> SpecifiedValue {
        SpecifiedValue(RepeatKeyword::Stretch, None)
    }

    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, _context: &Context) -> computed_value::T {
            computed_value::T(self.0, self.1.unwrap_or(self.0))
        }
        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            SpecifiedValue(computed.0, Some(computed.1))
        }
    }

    pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                         -> Result<SpecifiedValue, ParseError<'i>> {
        let first = RepeatKeyword::parse(input)?;
        let second = input.try(RepeatKeyword::parse).ok();

        Ok(SpecifiedValue(first, second))
    }
</%helpers:longhand>

${helpers.predefined_type("border-image-width", "BorderImageWidth",
    initial_value="computed::BorderImageSideWidth::one().into()",
    initial_specified_value="specified::BorderImageSideWidth::one().into()",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
    animation_value_type="discrete",
    boxed=True)}

${helpers.predefined_type("border-image-slice", "BorderImageSlice",
    initial_value="computed::NumberOrPercentage::Percentage(computed::Percentage(1.)).into()",
    initial_specified_value="specified::NumberOrPercentage::Percentage(specified::Percentage::new(1.)).into()",
    spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
    animation_value_type="discrete",
    boxed=True)}

#[cfg(feature = "gecko")]
impl ::values::computed::BorderImageWidth {
    pub fn to_gecko_rect(&self, sides: &mut ::gecko_bindings::structs::nsStyleSides) {
        use gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue};
        use gecko::values::GeckoStyleCoordConvertible;
        use values::generics::border::BorderImageSideWidth;

        % for i in range(0, 4):
        match self.${i} {
            BorderImageSideWidth::Auto => {
                sides.data_at_mut(${i}).set_value(CoordDataValue::Auto)
            },
            BorderImageSideWidth::Length(l) => {
                l.to_gecko_style_coord(&mut sides.data_at_mut(${i}))
            },
            BorderImageSideWidth::Number(n) => {
                sides.data_at_mut(${i}).set_value(CoordDataValue::Factor(n))
            },
        }
        % endfor
    }

    pub fn from_gecko_rect(sides: &::gecko_bindings::structs::nsStyleSides)
                           -> Option<::values::computed::BorderImageWidth> {
        use gecko_bindings::structs::nsStyleUnit::{eStyleUnit_Factor, eStyleUnit_Auto};
        use gecko_bindings::sugar::ns_style_coord::CoordData;
        use gecko::values::GeckoStyleCoordConvertible;
        use values::computed::{LengthOrPercentage, Number};
        use values::generics::border::BorderImageSideWidth;

        Some(
            ::values::computed::BorderImageWidth::new(
                % for i in range(0, 4):
                match sides.data_at(${i}).unit() {
                    eStyleUnit_Auto => {
                        BorderImageSideWidth::Auto
                    },
                    eStyleUnit_Factor => {
                        BorderImageSideWidth::Number(
                            Number::from_gecko_style_coord(&sides.data_at(${i}))
                                .expect("sides[${i}] could not convert to Number"))
                    },
                    _ => {
                        BorderImageSideWidth::Length(
                            LengthOrPercentage::from_gecko_style_coord(&sides.data_at(${i}))
                                .expect("sides[${i}] could not convert to LengthOrPercentager"))
                    },
                },
                % endfor
            )
        )
    }
}
<|endoftext|>