<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 https://mozilla.org/MPL/2.0/. */

//! Tracking of pending loads in a document.
//!
//! <https://html.spec.whatwg.org/multipage/#the-end>

use crate::dom::bindings::root::Dom;
use crate::dom::document::Document;
use crate::fetch::FetchCanceller;
use ipc_channel::ipc::IpcSender;
use net_traits::request::RequestInit;
use net_traits::{CoreResourceMsg, FetchChannels, FetchResponseMsg};
use net_traits::{IpcSend, ResourceThreads};
use servo_url::ServoUrl;
use std::thread;

#[derive(Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)]
pub enum LoadType {
    Image(ServoUrl),
    Script(ServoUrl),
    Subframe(ServoUrl),
    Stylesheet(ServoUrl),
    PageSource(ServoUrl),
    Media,
}

impl LoadType {
    fn url(&self) -> Option<&ServoUrl> {
        match *self {
            LoadType::Image(ref url) |
            LoadType::Script(ref url) |
            LoadType::Subframe(ref url) |
            LoadType::Stylesheet(ref url) |
            LoadType::PageSource(ref url) => Some(url),
            LoadType::Media => None,
        }
    }
}

/// Canary value ensuring that manually added blocking loads (ie. ones that weren't
/// created via DocumentLoader::fetch_async) are always removed by the time
/// that the owner is destroyed.
#[derive(JSTraceable, MallocSizeOf)]
#[must_root]
pub struct LoadBlocker {
    /// The document whose load event is blocked by this object existing.
    doc: Dom<Document>,
    /// The load that is blocking the document's load event.
    load: Option<LoadType>,
}

impl LoadBlocker {
    /// Mark the document's load event as blocked on this new load.
    pub fn new(doc: &Document, load: LoadType) -> LoadBlocker {
        doc.loader_mut().add_blocking_load(load.clone());
        LoadBlocker {
            doc: Dom::from_ref(doc),
            load: Some(load),
        }
    }

    /// Remove this load from the associated document's list of blocking loads.
    pub fn terminate(blocker: &mut Option<LoadBlocker>) {
        if let Some(this) = blocker.as_mut() {
            this.doc.finish_load(this.load.take().unwrap());
        }
        *blocker = None;
    }

    /// Return the url associated with this load.
    pub fn url(&self) -> Option<&ServoUrl> {
        self.load.as_ref().and_then(LoadType::url)
    }
}

impl Drop for LoadBlocker {
    fn drop(&mut self) {
        if !thread::panicking() {
            debug_assert!(self.load.is_none());
        }
    }
}

#[derive(JSTraceable, MallocSizeOf)]
pub struct DocumentLoader {
    resource_threads: ResourceThreads,
    blocking_loads: Vec<LoadType>,
    events_inhibited: bool,
    cancellers: Vec<FetchCanceller>,
}

impl DocumentLoader {
    pub fn new(existing: &DocumentLoader) -> DocumentLoader {
        DocumentLoader::new_with_threads(existing.resource_threads.clone(), None)
    }

    pub fn new_with_threads(
        resource_threads: ResourceThreads,
        initial_load: Option<ServoUrl>,
    ) -> DocumentLoader {
        debug!("Initial blocking load {:?}.", initial_load);
        let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();

        DocumentLoader {
            resource_threads: resource_threads,
            blocking_loads: initial_loads,
            events_inhibited: false,
            cancellers: Vec::new(),
        }
    }

    pub fn cancel_all_loads(&mut self) -> bool {
        let canceled_any = !self.cancellers.is_empty();
        // Associated fetches will be canceled when dropping the canceller.
        self.cancellers.clear();
        canceled_any
    }

    /// Add a load to the list of blocking loads.
    fn add_blocking_load(&mut self, load: LoadType) {
        debug!(
            "Adding blocking load {:?} ({}).",
            load,
            self.blocking_loads.len()
        );
        self.blocking_loads.push(load);
    }

    /// Initiate a new fetch.
    pub fn fetch_async(
        &mut self,
        load: LoadType,
        request: RequestInit,
        fetch_target: IpcSender<FetchResponseMsg>,
    ) {
        self.add_blocking_load(load);
        self.fetch_async_background(request, fetch_target);
    }

    /// Initiate a new fetch that does not block the document load event.
    pub fn fetch_async_background(
        &mut self,
        request: RequestInit,
        fetch_target: IpcSender<FetchResponseMsg>,
    ) {
        let mut canceller = FetchCanceller::new();
        let cancel_receiver = canceller.initialize();
        self.cancellers.push(canceller);
        self.resource_threads
            .sender()
            .send(CoreResourceMsg::Fetch(
                request,
                FetchChannels::ResponseMsg(fetch_target, Some(cancel_receiver)),
            ))
            .unwrap();
    }

    /// Mark an in-progress network request complete.
    pub fn finish_load(&mut self, load: &LoadType) {
        debug!(
            "Removing blocking load {:?} ({}).",
            load,
            self.blocking_loads.len()
        );
        let idx = self
            .blocking_loads
            .iter()
            .position(|unfinished| *unfinished == *load);
        self.blocking_loads
            .remove(idx.unwrap_or_else(|| panic!("unknown completed load {:?}", load)));
    }

    pub fn is_blocked(&self) -> bool {
        // TODO: Ensure that we report blocked if parsing is still ongoing.
        !self.blocking_loads.is_empty()
    }

    pub fn is_only_blocked_by_iframes(&self) -> bool {
        self.blocking_loads.iter().all(|load| match *load {
            LoadType::Subframe(_) => true,
            _ => false,
        })
    }

    pub fn inhibit_events(&mut self) {
        self.events_inhibited = true;
    }

    pub fn events_inhibited(&self) -> bool {
        self.events_inhibited
    }

    pub fn resource_threads(&self) -> &ResourceThreads {
        &self.resource_threads
    }
}
<commit_msg>removed spurrious assert in Drop for LoadBlocker<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 https://mozilla.org/MPL/2.0/. */

//! Tracking of pending loads in a document.
//!
//! <https://html.spec.whatwg.org/multipage/#the-end>

use crate::dom::bindings::root::Dom;
use crate::dom::document::Document;
use crate::fetch::FetchCanceller;
use ipc_channel::ipc::IpcSender;
use net_traits::request::RequestInit;
use net_traits::{CoreResourceMsg, FetchChannels, FetchResponseMsg};
use net_traits::{IpcSend, ResourceThreads};
use servo_url::ServoUrl;
use std::thread;

#[derive(Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)]
pub enum LoadType {
    Image(ServoUrl),
    Script(ServoUrl),
    Subframe(ServoUrl),
    Stylesheet(ServoUrl),
    PageSource(ServoUrl),
    Media,
}

impl LoadType {
    fn url(&self) -> Option<&ServoUrl> {
        match *self {
            LoadType::Image(ref url) |
            LoadType::Script(ref url) |
            LoadType::Subframe(ref url) |
            LoadType::Stylesheet(ref url) |
            LoadType::PageSource(ref url) => Some(url),
            LoadType::Media => None,
        }
    }
}

/// Canary value ensuring that manually added blocking loads (ie. ones that weren't
/// created via DocumentLoader::fetch_async) are always removed by the time
/// that the owner is destroyed.
#[derive(JSTraceable, MallocSizeOf)]
#[must_root]
pub struct LoadBlocker {
    /// The document whose load event is blocked by this object existing.
    doc: Dom<Document>,
    /// The load that is blocking the document's load event.
    load: Option<LoadType>,
}

impl LoadBlocker {
    /// Mark the document's load event as blocked on this new load.
    pub fn new(doc: &Document, load: LoadType) -> LoadBlocker {
        doc.loader_mut().add_blocking_load(load.clone());
        LoadBlocker {
            doc: Dom::from_ref(doc),
            load: Some(load),
        }
    }

    /// Remove this load from the associated document's list of blocking loads.
    pub fn terminate(blocker: &mut Option<LoadBlocker>) {
        if let Some(this) = blocker.as_mut() {
            this.doc.finish_load(this.load.take().unwrap());
        }
        *blocker = None;
    }

    /// Return the url associated with this load.
    pub fn url(&self) -> Option<&ServoUrl> {
        self.load.as_ref().and_then(LoadType::url)
    }
}

impl Drop for LoadBlocker {
    fn drop(&mut self) {
        if let Some(script_thread) = self.load.take() {
            self.doc.finish_load(script_thread);
        }
    }
}

#[derive(JSTraceable, MallocSizeOf)]
pub struct DocumentLoader {
    resource_threads: ResourceThreads,
    blocking_loads: Vec<LoadType>,
    events_inhibited: bool,
    cancellers: Vec<FetchCanceller>,
}

impl DocumentLoader {
    pub fn new(existing: &DocumentLoader) -> DocumentLoader {
        DocumentLoader::new_with_threads(existing.resource_threads.clone(), None)
    }

    pub fn new_with_threads(
        resource_threads: ResourceThreads,
        initial_load: Option<ServoUrl>,
    ) -> DocumentLoader {
        debug!("Initial blocking load {:?}.", initial_load);
        let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();

        DocumentLoader {
            resource_threads: resource_threads,
            blocking_loads: initial_loads,
            events_inhibited: false,
            cancellers: Vec::new(),
        }
    }

    pub fn cancel_all_loads(&mut self) -> bool {
        let canceled_any = !self.cancellers.is_empty();
        // Associated fetches will be canceled when dropping the canceller.
        self.cancellers.clear();
        canceled_any
    }

    /// Add a load to the list of blocking loads.
    fn add_blocking_load(&mut self, load: LoadType) {
        debug!(
            "Adding blocking load {:?} ({}).",
            load,
            self.blocking_loads.len()
        );
        self.blocking_loads.push(load);
    }

    /// Initiate a new fetch.
    pub fn fetch_async(
        &mut self,
        load: LoadType,
        request: RequestInit,
        fetch_target: IpcSender<FetchResponseMsg>,
    ) {
        self.add_blocking_load(load);
        self.fetch_async_background(request, fetch_target);
    }

    /// Initiate a new fetch that does not block the document load event.
    pub fn fetch_async_background(
        &mut self,
        request: RequestInit,
        fetch_target: IpcSender<FetchResponseMsg>,
    ) {
        let mut canceller = FetchCanceller::new();
        let cancel_receiver = canceller.initialize();
        self.cancellers.push(canceller);
        self.resource_threads
            .sender()
            .send(CoreResourceMsg::Fetch(
                request,
                FetchChannels::ResponseMsg(fetch_target, Some(cancel_receiver)),
            ))
            .unwrap();
    }

    /// Mark an in-progress network request complete.
    pub fn finish_load(&mut self, load: &LoadType) {
        debug!(
            "Removing blocking load {:?} ({}).",
            load,
            self.blocking_loads.len()
        );
        let idx = self
            .blocking_loads
            .iter()
            .position(|unfinished| *unfinished == *load);
        self.blocking_loads
            .remove(idx.unwrap_or_else(|| panic!("unknown completed load {:?}", load)));
    }

    pub fn is_blocked(&self) -> bool {
        // TODO: Ensure that we report blocked if parsing is still ongoing.
        !self.blocking_loads.is_empty()
    }

    pub fn is_only_blocked_by_iframes(&self) -> bool {
        self.blocking_loads.iter().all(|load| match *load {
            LoadType::Subframe(_) => true,
            _ => false,
        })
    }

    pub fn inhibit_events(&mut self) {
        self.events_inhibited = true;
    }

    pub fn events_inhibited(&self) -> bool {
        self.events_inhibited
    }

    pub fn resource_threads(&self) -> &ResourceThreads {
        &self.resource_threads
    }
}
<|endoftext|>


<commit_before>//! Diagnostic reporting support for the codespan crate.

use std::ops::Range;

pub mod diagnostic;
pub mod term;

/// A location in a source file.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Location {
    /// The line number in the source file.
    pub line_number: usize,
    /// The column number in the source file.
    pub column_number: usize,
}

/// A line within a source file.
pub struct Line<Source> {
    /// The starting byte index of the line.
    pub start: usize,
    /// The line number.
    pub number: usize,
    /// The source of the line.
    pub source: Source,
}

impl<Source> Line<Source>
where
    Source: AsRef<str>,
{
    pub fn column_index(&self, byte_index: usize) -> Option<usize> {
        match byte_index.checked_sub(self.start) {
            None => Some(0),
            Some(relative_index) => {
                let source = self.source.as_ref().get(..relative_index)?;
                Some(source.chars().count())
            },
        }
    }

    pub fn column_number(&self, byte_index: usize) -> Option<usize> {
        Some(self.column_index(byte_index)? + 1)
    }
}

/// Files that can be used for pretty printing.
pub trait Files {
    type FileId: Copy + PartialEq + PartialOrd + Eq + Ord + std::hash::Hash;
    type Origin: std::fmt::Display;
    type LineSource: AsRef<str>;

    /// The origin of a file.
    fn origin(&self, id: Self::FileId) -> Option<Self::Origin>;

    /// The line at the given index.
    fn line(&self, id: Self::FileId, line_index: usize) -> Option<Line<Self::LineSource>>;

    /// The index of the line at the given byte index.
    fn line_index(&self, id: Self::FileId, byte_index: usize) -> Option<usize>;

    /// The location of the given byte index.
    fn location(&self, id: Self::FileId, byte_index: usize) -> Option<Location> {
        let line_index = self.line_index(id, byte_index)?;
        let line = self.line(id, line_index)?;

        Some(Location {
            line_number: line.number,
            column_number: line.column_number(byte_index)?,
        })
    }
}

/// A single source file.
///
/// This is useful for simple language tests, but it might be worth creating a
/// custom implementation when a language scales beyond a certain size.
#[derive(Debug, Clone)]
pub struct SimpleFile<Origin, Source> {
    /// The origin of the file.
    origin: Origin,
    /// The source code of the file.
    source: Source,
    /// The starting byte indices in the source code.
    line_starts: Vec<usize>,
}

fn line_starts<'a>(source: &'a str) -> impl 'a + Iterator<Item = usize> {
    std::iter::once(0).chain(source.match_indices('\n').map(|(i, _)| i + 1))
}

impl<Origin, Source> SimpleFile<Origin, Source>
where
    Origin: std::fmt::Display,
    Source: AsRef<str>,
{
    /// Create a new source file.
    pub fn new(origin: Origin, source: Source) -> SimpleFile<Origin, Source> {
        SimpleFile {
            origin,
            line_starts: line_starts(source.as_ref()).collect(),
            source,
        }
    }

    fn line_start(&self, line_index: usize) -> Option<usize> {
        use std::cmp::Ordering;

        match line_index.cmp(&self.line_starts.len()) {
            Ordering::Less => Some(self.line_starts[line_index]),
            Ordering::Equal => Some(self.source.as_ref().len()),
            Ordering::Greater => None,
        }
    }

    fn line_range(&self, line_index: usize) -> Option<Range<usize>> {
        let line_start = self.line_start(line_index)?;
        let next_line_start = self.line_start(line_index + 1)?;

        Some(line_start..next_line_start)
    }
}

impl<Origin, Source> Files for SimpleFile<Origin, Source>
where
    Origin: std::fmt::Display + Clone,
    Source: AsRef<str>,
{
    type FileId = ();
    type Origin = Origin;
    type LineSource = String;

    fn origin(&self, (): ()) -> Option<Origin> {
        Some(self.origin.clone())
    }

    fn line_index(&self, (): (), byte_index: usize) -> Option<usize> {
        match self.line_starts.binary_search(&byte_index) {
            Ok(line) => Some(line),
            Err(next_line) => Some(next_line - 1),
        }
    }

    fn line(&self, (): (), line_index: usize) -> Option<Line<String>> {
        let range = self.line_range(line_index)?;

        Some(Line {
            start: range.start,
            number: line_index + 1,
            source: self.source.as_ref()[range].to_owned(),
        })
    }
}

/// A file database that can store multiple source files.
///
/// This is useful for simple language tests, but it might be worth creating a
/// custom implementation when a language scales beyond a certain size.
#[derive(Debug, Clone)]
pub struct SimpleFiles<Origin, Source> {
    files: Vec<SimpleFile<Origin, Source>>,
}

impl<Origin, Source> SimpleFiles<Origin, Source>
where
    Origin: std::fmt::Display,
    Source: AsRef<str>,
{
    /// Create a new files database.
    pub fn new() -> SimpleFiles<Origin, Source> {
        SimpleFiles { files: Vec::new() }
    }

    /// Add a file to the database, returning the handle that can be used to
    /// refer to it again.
    pub fn add(&mut self, origin: Origin, source: Source) -> usize {
        let file_id = self.files.len();
        self.files.push(SimpleFile::new(origin, source));
        file_id
    }
}

impl<Origin, Source> Files for SimpleFiles<Origin, Source>
where
    Origin: std::fmt::Display + Clone,
    Source: AsRef<str>,
{
    type FileId = usize;
    type Origin = Origin;
    type LineSource = String;

    fn origin(&self, file_id: usize) -> Option<Origin> {
        self.files.get(file_id)?.origin(())
    }

    fn line_index(&self, file_id: usize, byte_index: usize) -> Option<usize> {
        self.files.get(file_id)?.line_index((), byte_index)
    }

    fn line(&self, file_id: usize, line_index: usize) -> Option<Line<String>> {
        self.files.get(file_id)?.line((), line_index)
    }
}
<commit_msg>Add documentation to Line methods<commit_after>//! Diagnostic reporting support for the codespan crate.

use std::ops::Range;

pub mod diagnostic;
pub mod term;

/// A location in a source file.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Location {
    /// The line number in the source file.
    pub line_number: usize,
    /// The column number in the source file.
    pub column_number: usize,
}

/// A line within a source file.
pub struct Line<Source> {
    /// The starting byte index of the line.
    pub start: usize,
    /// The line number.
    pub number: usize,
    /// The source of the line.
    pub source: Source,
}

impl<Source> Line<Source>
where
    Source: AsRef<str>,
{
    /// The column index at the given byte index in the source file.
    /// This is the number of characters to the given byte index.
    ///
    /// If the byte index is smaller than the start of the line, then `0` is returned.
    /// If the byte index is past the end of the line, the column index of the last
    /// character `+ 1` is returned.
    ///
    /// # Example
    ///
    /// ```rust
    /// use codespan_reporting::Line;
    ///
    /// let line = Line {
    ///     start: 2,
    ///     number: 2,
    ///     source: "🗻∈🌏",
    /// };
    ///
    /// assert_eq!(line.column_index(0), 0);
    /// assert_eq!(line.column_index(line.start + 0), 0);
    /// // FIXME: Snap column index to the previous character boundary
    /// // assert_eq!(line.column_index(line.start + 1), 0);
    /// assert_eq!(line.column_index(line.start + 4), 1);
    /// assert_eq!(line.column_index(line.start + 8), 3);
    /// assert_eq!(line.column_index(line.start + 48), 3);
    /// ```
    pub fn column_index(&self, byte_index: usize) -> usize {
        match byte_index.checked_sub(self.start) {
            None => 0,
            Some(relative_index) => {
                let line_source = self.source.as_ref();

                line_source
                    .char_indices()
                    .map(|(i, _)| i)
                    .take_while(|i| *i < relative_index)
                    .count()
            },
        }
    }

    /// The 1-indexed column number at the given byte index.
    pub fn column_number(&self, byte_index: usize) -> usize {
        self.column_index(byte_index) + 1
    }
}

/// Files that can be used for pretty printing.
pub trait Files {
    type FileId: Copy + PartialEq + PartialOrd + Eq + Ord + std::hash::Hash;
    type Origin: std::fmt::Display;
    type LineSource: AsRef<str>;

    /// The origin of a file.
    fn origin(&self, id: Self::FileId) -> Option<Self::Origin>;

    /// The line at the given index.
    fn line(&self, id: Self::FileId, line_index: usize) -> Option<Line<Self::LineSource>>;

    /// The index of the line at the given byte index.
    fn line_index(&self, id: Self::FileId, byte_index: usize) -> Option<usize>;

    /// The location of the given byte index.
    fn location(&self, id: Self::FileId, byte_index: usize) -> Option<Location> {
        let line_index = self.line_index(id, byte_index)?;
        let line = self.line(id, line_index)?;

        Some(Location {
            line_number: line.number,
            column_number: line.column_number(byte_index),
        })
    }
}

/// A single source file.
///
/// This is useful for simple language tests, but it might be worth creating a
/// custom implementation when a language scales beyond a certain size.
#[derive(Debug, Clone)]
pub struct SimpleFile<Origin, Source> {
    /// The origin of the file.
    origin: Origin,
    /// The source code of the file.
    source: Source,
    /// The starting byte indices in the source code.
    line_starts: Vec<usize>,
}

fn line_starts<'a>(source: &'a str) -> impl 'a + Iterator<Item = usize> {
    std::iter::once(0).chain(source.match_indices('\n').map(|(i, _)| i + 1))
}

impl<Origin, Source> SimpleFile<Origin, Source>
where
    Origin: std::fmt::Display,
    Source: AsRef<str>,
{
    /// Create a new source file.
    pub fn new(origin: Origin, source: Source) -> SimpleFile<Origin, Source> {
        SimpleFile {
            origin,
            line_starts: line_starts(source.as_ref()).collect(),
            source,
        }
    }

    fn line_start(&self, line_index: usize) -> Option<usize> {
        use std::cmp::Ordering;

        match line_index.cmp(&self.line_starts.len()) {
            Ordering::Less => Some(self.line_starts[line_index]),
            Ordering::Equal => Some(self.source.as_ref().len()),
            Ordering::Greater => None,
        }
    }

    fn line_range(&self, line_index: usize) -> Option<Range<usize>> {
        let line_start = self.line_start(line_index)?;
        let next_line_start = self.line_start(line_index + 1)?;

        Some(line_start..next_line_start)
    }
}

impl<Origin, Source> Files for SimpleFile<Origin, Source>
where
    Origin: std::fmt::Display + Clone,
    Source: AsRef<str>,
{
    type FileId = ();
    type Origin = Origin;
    type LineSource = String;

    fn origin(&self, (): ()) -> Option<Origin> {
        Some(self.origin.clone())
    }

    fn line_index(&self, (): (), byte_index: usize) -> Option<usize> {
        match self.line_starts.binary_search(&byte_index) {
            Ok(line) => Some(line),
            Err(next_line) => Some(next_line - 1),
        }
    }

    fn line(&self, (): (), line_index: usize) -> Option<Line<String>> {
        let range = self.line_range(line_index)?;

        Some(Line {
            start: range.start,
            number: line_index + 1,
            source: self.source.as_ref()[range].to_owned(),
        })
    }
}

/// A file database that can store multiple source files.
///
/// This is useful for simple language tests, but it might be worth creating a
/// custom implementation when a language scales beyond a certain size.
#[derive(Debug, Clone)]
pub struct SimpleFiles<Origin, Source> {
    files: Vec<SimpleFile<Origin, Source>>,
}

impl<Origin, Source> SimpleFiles<Origin, Source>
where
    Origin: std::fmt::Display,
    Source: AsRef<str>,
{
    /// Create a new files database.
    pub fn new() -> SimpleFiles<Origin, Source> {
        SimpleFiles { files: Vec::new() }
    }

    /// Add a file to the database, returning the handle that can be used to
    /// refer to it again.
    pub fn add(&mut self, origin: Origin, source: Source) -> usize {
        let file_id = self.files.len();
        self.files.push(SimpleFile::new(origin, source));
        file_id
    }
}

impl<Origin, Source> Files for SimpleFiles<Origin, Source>
where
    Origin: std::fmt::Display + Clone,
    Source: AsRef<str>,
{
    type FileId = usize;
    type Origin = Origin;
    type LineSource = String;

    fn origin(&self, file_id: usize) -> Option<Origin> {
        self.files.get(file_id)?.origin(())
    }

    fn line_index(&self, file_id: usize, byte_index: usize) -> Option<usize> {
        self.files.get(file_id)?.line_index((), byte_index)
    }

    fn line(&self, file_id: usize, line_index: usize) -> Option<Line<String>> {
        self.files.get(file_id)?.line((), line_index)
    }
}
<|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/. */

//! Keyframes: https://drafts.csswg.org/css-animations/#keyframes

#![deny(missing_docs)]

use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
use parking_lot::RwLock;
use parser::{ParserContext, ParserContextExtraData, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
use properties::{PropertyDeclarationId, LonghandId, DeclaredValue};
use properties::PropertyDeclarationParseResult;
use properties::animated_properties::TransitionProperty;
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
use std::fmt;
use std::sync::Arc;
use style_traits::ToCss;
use stylesheets::{MemoryHoleReporter, Stylesheet};

/// A number from 0 to 1, indicating the percentage of the animation when this
/// keyframe should run.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframePercentage(pub f32);

impl ::std::cmp::Ord for KeyframePercentage {
    #[inline]
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        // We know we have a number from 0 to 1, so unwrap() here is safe.
        self.0.partial_cmp(&other.0).unwrap()
    }
}

impl ::std::cmp::Eq for KeyframePercentage { }

impl ToCss for KeyframePercentage {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        write!(dest, "{}%", self.0 * 100.0)
    }
}

impl KeyframePercentage {
    /// Trivially constructs a new `KeyframePercentage`.
    #[inline]
    pub fn new(value: f32) -> KeyframePercentage {
        debug_assert!(value >= 0. && value <= 1.);
        KeyframePercentage(value)
    }

    fn parse(input: &mut Parser) -> Result<KeyframePercentage, ()> {
        let percentage = if input.try(|input| input.expect_ident_matching("from")).is_ok() {
            KeyframePercentage::new(0.)
        } else if input.try(|input| input.expect_ident_matching("to")).is_ok() {
            KeyframePercentage::new(1.)
        } else {
            let percentage = try!(input.expect_percentage());
            if percentage >= 0. && percentage <= 1. {
                KeyframePercentage::new(percentage)
            } else {
                return Err(());
            }
        };

        Ok(percentage)
    }
}

/// A keyframes selector is a list of percentages or from/to symbols, which are
/// converted at parse time to percentages.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframeSelector(Vec<KeyframePercentage>);
impl KeyframeSelector {
    /// Return the list of percentages this selector contains.
    #[inline]
    pub fn percentages(&self) -> &[KeyframePercentage] {
        &self.0
    }

    /// A dummy public function so we can write a unit test for this.
    pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
        KeyframeSelector(percentages)
    }

    /// Parse a keyframe selector from CSS input.
    pub fn parse(input: &mut Parser) -> Result<Self, ()> {
        input.parse_comma_separated(KeyframePercentage::parse)
             .map(KeyframeSelector)
    }
}

/// A keyframe.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Keyframe {
    /// The selector this keyframe was specified from.
    pub selector: KeyframeSelector,

    /// The declaration block that was declared inside this keyframe.
    ///
    /// Note that `!important` rules in keyframes don't apply, but we keep this
    /// `Arc` just for convenience.
    #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
    pub block: Arc<RwLock<PropertyDeclarationBlock>>,
}

impl ToCss for Keyframe {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        let mut iter = self.selector.percentages().iter();
        try!(iter.next().unwrap().to_css(dest));
        for percentage in iter {
            try!(write!(dest, ", "));
            try!(percentage.to_css(dest));
        }
        try!(dest.write_str(" { "));
        try!(self.block.read().to_css(dest));
        try!(dest.write_str(" }"));
        Ok(())
    }
}

impl Keyframe {
    /// Parse a CSS keyframe.
    pub fn parse(css: &str,
                 parent_stylesheet: &Stylesheet,
                 extra_data: ParserContextExtraData)
                 -> Result<Arc<RwLock<Self>>, ()> {
        let error_reporter = Box::new(MemoryHoleReporter);
        let context = ParserContext::new_with_extra_data(parent_stylesheet.origin,
                                                         &parent_stylesheet.base_url,
                                                         error_reporter,
                                                         extra_data);
        let mut input = Parser::new(css);

        let mut rule_parser = KeyframeListParser {
            context: &context,
        };
        parse_one_rule(&mut input, &mut rule_parser)
    }
}

/// A keyframes step value. This can be a synthetised keyframes animation, that
/// is, one autogenerated from the current computed values, or a list of
/// declarations to apply.
///
/// TODO: Find a better name for this?
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesStepValue {
    /// A step formed by a declaration block specified by the CSS.
    Declarations {
        /// The declaration block per se.
        #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
        block: Arc<RwLock<PropertyDeclarationBlock>>
    },
    /// A synthetic step computed from the current computed values at the time
    /// of the animation.
    ComputedValues,
}

/// A single step from a keyframe animation.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesStep {
    /// The percentage of the animation duration when this step starts.
    pub start_percentage: KeyframePercentage,
    /// Declarations that will determine the final style during the step, or
    /// `ComputedValues` if this is an autogenerated step.
    pub value: KeyframesStepValue,
    /// Wether a animation-timing-function declaration exists in the list of
    /// declarations.
    ///
    /// This is used to know when to override the keyframe animation style.
    pub declared_timing_function: bool,
}

impl KeyframesStep {
    #[inline]
    fn new(percentage: KeyframePercentage,
           value: KeyframesStepValue) -> Self {
        let declared_timing_function = match value {
            KeyframesStepValue::Declarations { ref block } => {
                block.read().declarations.iter().any(|&(ref prop_decl, _)| {
                    match *prop_decl {
                        PropertyDeclaration::AnimationTimingFunction(..) => true,
                        _ => false,
                    }
                })
            }
            _ => false,
        };

        KeyframesStep {
            start_percentage: percentage,
            value: value,
            declared_timing_function: declared_timing_function,
        }
    }

    /// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'.
    pub fn get_animation_timing_function(&self) -> Option<SpecifiedTimingFunction> {
        if !self.declared_timing_function {
            return None;
        }
        match self.value {
            KeyframesStepValue::Declarations { ref block } => {
                let guard = block.read();
                let &(ref declaration, _) =
                    guard.get(PropertyDeclarationId::Longhand(LonghandId::AnimationTimingFunction)).unwrap();
                match *declaration {
                    PropertyDeclaration::AnimationTimingFunction(ref value) => {
                        match *value {
                            DeclaredValue::Value(ref value) => {
                                // Use the first value.
                                Some(value.0[0])
                            },
                            _ => None,
                        }
                    },
                    _ => panic!(),
                }
            },
            KeyframesStepValue::ComputedValues => {
                panic!("Shouldn't happen to set animation-timing-function in missing keyframes")
            },
        }
    }
}

/// This structure represents a list of animation steps computed from the list
/// of keyframes, in order.
///
/// It only takes into account animable properties.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesAnimation {
    /// The difference steps of the animation.
    pub steps: Vec<KeyframesStep>,
    /// The properties that change in this animation.
    pub properties_changed: Vec<TransitionProperty>,
}

/// Get all the animated properties in a keyframes animation. Note that it's not
/// defined what happens when a property is not on a keyframe, so we only peek
/// the props of the first one.
///
/// In practice, browsers seem to try to do their best job at it, so we might
/// want to go through all the actual keyframes and deduplicate properties.
fn get_animated_properties(keyframe: &Keyframe) -> Vec<TransitionProperty> {
    let mut ret = vec![];
    // NB: declarations are already deduplicated, so we don't have to check for
    // it here.
    for &(ref declaration, _) in keyframe.block.read().declarations.iter() {
        if let Some(property) = TransitionProperty::from_declaration(declaration) {
            ret.push(property);
        }
    }

    ret
}

impl KeyframesAnimation {
    /// Create a keyframes animation from a given list of keyframes.
    ///
    /// This will return `None` if the list of keyframes is empty, or there are
    /// no animated properties obtained from the keyframes.
    ///
    /// Otherwise, this will compute and sort the steps used for the animation,
    /// and return the animation object.
    pub fn from_keyframes(keyframes: &[Arc<RwLock<Keyframe>>]) -> Option<Self> {
        if keyframes.is_empty() {
            return None;
        }

        let animated_properties = get_animated_properties(&keyframes[0].read());
        if animated_properties.is_empty() {
            return None;
        }

        let mut steps = vec![];

        for keyframe in keyframes {
            let keyframe = keyframe.read();
            for percentage in keyframe.selector.0.iter() {
                steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations {
                    block: keyframe.block.clone(),
                }));
            }
        }

        // Sort by the start percentage, so we can easily find a frame.
        steps.sort_by_key(|step| step.start_percentage);

        // Prepend autogenerated keyframes if appropriate.
        if steps[0].start_percentage.0 != 0. {
            steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.),
                                               KeyframesStepValue::ComputedValues));
        }

        if steps.last().unwrap().start_percentage.0 != 1. {
            steps.push(KeyframesStep::new(KeyframePercentage::new(0.),
                                          KeyframesStepValue::ComputedValues));
        }

        Some(KeyframesAnimation {
            steps: steps,
            properties_changed: animated_properties,
        })
    }
}

/// Parses a keyframes list, like:
/// 0%, 50% {
///     width: 50%;
/// }
///
/// 40%, 60%, 100% {
///     width: 100%;
/// }
struct KeyframeListParser<'a> {
    context: &'a ParserContext<'a>,
}

/// Parses a keyframe list from CSS input.
pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Vec<Arc<RwLock<Keyframe>>> {
    RuleListParser::new_for_nested_rule(input, KeyframeListParser { context: context })
        .filter_map(Result::ok)
        .collect()
}

enum Void {}
impl<'a> AtRuleParser for KeyframeListParser<'a> {
    type Prelude = Void;
    type AtRule = Arc<RwLock<Keyframe>>;
}

impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
    type Prelude = KeyframeSelector;
    type QualifiedRule = Arc<RwLock<Keyframe>>;

    fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> {
        let start = input.position();
        match KeyframeSelector::parse(input) {
            Ok(sel) => Ok(sel),
            Err(()) => {
                let message = format!("Invalid keyframe rule: '{}'", input.slice_from(start));
                log_css_error(input, start, &message, self.context);
                Err(())
            }
        }
    }

    fn parse_block(&mut self, prelude: Self::Prelude, input: &mut Parser)
                   -> Result<Self::QualifiedRule, ()> {
        let parser = KeyframeDeclarationParser {
            context: self.context,
            declarations: vec![],
        };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            match declaration {
                Ok(_) => (),
                Err(range) => {
                    let pos = range.start;
                    let message = format!("Unsupported keyframe property declaration: '{}'",
                                          iter.input.slice(range));
                    log_css_error(iter.input, pos, &*message, self.context);
                }
            }
            // `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
        }
        Ok(Arc::new(RwLock::new(Keyframe {
            selector: prelude,
            block: Arc::new(RwLock::new(PropertyDeclarationBlock {
                declarations: iter.parser.declarations,
                important_count: 0,
            })),
        })))
    }
}

struct KeyframeDeclarationParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
    declarations: Vec<(PropertyDeclaration, Importance)>
}

/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for KeyframeDeclarationParser<'a, 'b> {
    type Prelude = ();
    type AtRule = ();
}

impl<'a, 'b> DeclarationParser for KeyframeDeclarationParser<'a, 'b> {
    /// We parse rules directly into the declarations object
    type Declaration = ();

    fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
        let id = try!(PropertyId::parse(name.into()));
        let old_len = self.declarations.len();
        match PropertyDeclaration::parse(id, self.context, input, &mut self.declarations, true) {
            PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}
            _ => {
                self.declarations.truncate(old_len);
                return Err(());
            }
        }
        // In case there is still unparsed text in the declaration, we should roll back.
        if !input.is_exhausted() {
            self.declarations.truncate(old_len);
            Err(())
        } else {
            Ok(())
        }
    }
}
<commit_msg>Bug 1328787 - Part 11: The last keyframe's KeyframePercentage is 1.0. r=heycam<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/. */

//! Keyframes: https://drafts.csswg.org/css-animations/#keyframes

#![deny(missing_docs)]

use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
use parking_lot::RwLock;
use parser::{ParserContext, ParserContextExtraData, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
use properties::{PropertyDeclarationId, LonghandId, DeclaredValue};
use properties::PropertyDeclarationParseResult;
use properties::animated_properties::TransitionProperty;
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
use std::fmt;
use std::sync::Arc;
use style_traits::ToCss;
use stylesheets::{MemoryHoleReporter, Stylesheet};

/// A number from 0 to 1, indicating the percentage of the animation when this
/// keyframe should run.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframePercentage(pub f32);

impl ::std::cmp::Ord for KeyframePercentage {
    #[inline]
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        // We know we have a number from 0 to 1, so unwrap() here is safe.
        self.0.partial_cmp(&other.0).unwrap()
    }
}

impl ::std::cmp::Eq for KeyframePercentage { }

impl ToCss for KeyframePercentage {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        write!(dest, "{}%", self.0 * 100.0)
    }
}

impl KeyframePercentage {
    /// Trivially constructs a new `KeyframePercentage`.
    #[inline]
    pub fn new(value: f32) -> KeyframePercentage {
        debug_assert!(value >= 0. && value <= 1.);
        KeyframePercentage(value)
    }

    fn parse(input: &mut Parser) -> Result<KeyframePercentage, ()> {
        let percentage = if input.try(|input| input.expect_ident_matching("from")).is_ok() {
            KeyframePercentage::new(0.)
        } else if input.try(|input| input.expect_ident_matching("to")).is_ok() {
            KeyframePercentage::new(1.)
        } else {
            let percentage = try!(input.expect_percentage());
            if percentage >= 0. && percentage <= 1. {
                KeyframePercentage::new(percentage)
            } else {
                return Err(());
            }
        };

        Ok(percentage)
    }
}

/// A keyframes selector is a list of percentages or from/to symbols, which are
/// converted at parse time to percentages.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframeSelector(Vec<KeyframePercentage>);
impl KeyframeSelector {
    /// Return the list of percentages this selector contains.
    #[inline]
    pub fn percentages(&self) -> &[KeyframePercentage] {
        &self.0
    }

    /// A dummy public function so we can write a unit test for this.
    pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
        KeyframeSelector(percentages)
    }

    /// Parse a keyframe selector from CSS input.
    pub fn parse(input: &mut Parser) -> Result<Self, ()> {
        input.parse_comma_separated(KeyframePercentage::parse)
             .map(KeyframeSelector)
    }
}

/// A keyframe.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Keyframe {
    /// The selector this keyframe was specified from.
    pub selector: KeyframeSelector,

    /// The declaration block that was declared inside this keyframe.
    ///
    /// Note that `!important` rules in keyframes don't apply, but we keep this
    /// `Arc` just for convenience.
    #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
    pub block: Arc<RwLock<PropertyDeclarationBlock>>,
}

impl ToCss for Keyframe {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        let mut iter = self.selector.percentages().iter();
        try!(iter.next().unwrap().to_css(dest));
        for percentage in iter {
            try!(write!(dest, ", "));
            try!(percentage.to_css(dest));
        }
        try!(dest.write_str(" { "));
        try!(self.block.read().to_css(dest));
        try!(dest.write_str(" }"));
        Ok(())
    }
}

impl Keyframe {
    /// Parse a CSS keyframe.
    pub fn parse(css: &str,
                 parent_stylesheet: &Stylesheet,
                 extra_data: ParserContextExtraData)
                 -> Result<Arc<RwLock<Self>>, ()> {
        let error_reporter = Box::new(MemoryHoleReporter);
        let context = ParserContext::new_with_extra_data(parent_stylesheet.origin,
                                                         &parent_stylesheet.base_url,
                                                         error_reporter,
                                                         extra_data);
        let mut input = Parser::new(css);

        let mut rule_parser = KeyframeListParser {
            context: &context,
        };
        parse_one_rule(&mut input, &mut rule_parser)
    }
}

/// A keyframes step value. This can be a synthetised keyframes animation, that
/// is, one autogenerated from the current computed values, or a list of
/// declarations to apply.
///
/// TODO: Find a better name for this?
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesStepValue {
    /// A step formed by a declaration block specified by the CSS.
    Declarations {
        /// The declaration block per se.
        #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
        block: Arc<RwLock<PropertyDeclarationBlock>>
    },
    /// A synthetic step computed from the current computed values at the time
    /// of the animation.
    ComputedValues,
}

/// A single step from a keyframe animation.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesStep {
    /// The percentage of the animation duration when this step starts.
    pub start_percentage: KeyframePercentage,
    /// Declarations that will determine the final style during the step, or
    /// `ComputedValues` if this is an autogenerated step.
    pub value: KeyframesStepValue,
    /// Wether a animation-timing-function declaration exists in the list of
    /// declarations.
    ///
    /// This is used to know when to override the keyframe animation style.
    pub declared_timing_function: bool,
}

impl KeyframesStep {
    #[inline]
    fn new(percentage: KeyframePercentage,
           value: KeyframesStepValue) -> Self {
        let declared_timing_function = match value {
            KeyframesStepValue::Declarations { ref block } => {
                block.read().declarations.iter().any(|&(ref prop_decl, _)| {
                    match *prop_decl {
                        PropertyDeclaration::AnimationTimingFunction(..) => true,
                        _ => false,
                    }
                })
            }
            _ => false,
        };

        KeyframesStep {
            start_percentage: percentage,
            value: value,
            declared_timing_function: declared_timing_function,
        }
    }

    /// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'.
    pub fn get_animation_timing_function(&self) -> Option<SpecifiedTimingFunction> {
        if !self.declared_timing_function {
            return None;
        }
        match self.value {
            KeyframesStepValue::Declarations { ref block } => {
                let guard = block.read();
                let &(ref declaration, _) =
                    guard.get(PropertyDeclarationId::Longhand(LonghandId::AnimationTimingFunction)).unwrap();
                match *declaration {
                    PropertyDeclaration::AnimationTimingFunction(ref value) => {
                        match *value {
                            DeclaredValue::Value(ref value) => {
                                // Use the first value.
                                Some(value.0[0])
                            },
                            _ => None,
                        }
                    },
                    _ => panic!(),
                }
            },
            KeyframesStepValue::ComputedValues => {
                panic!("Shouldn't happen to set animation-timing-function in missing keyframes")
            },
        }
    }
}

/// This structure represents a list of animation steps computed from the list
/// of keyframes, in order.
///
/// It only takes into account animable properties.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesAnimation {
    /// The difference steps of the animation.
    pub steps: Vec<KeyframesStep>,
    /// The properties that change in this animation.
    pub properties_changed: Vec<TransitionProperty>,
}

/// Get all the animated properties in a keyframes animation. Note that it's not
/// defined what happens when a property is not on a keyframe, so we only peek
/// the props of the first one.
///
/// In practice, browsers seem to try to do their best job at it, so we might
/// want to go through all the actual keyframes and deduplicate properties.
fn get_animated_properties(keyframe: &Keyframe) -> Vec<TransitionProperty> {
    let mut ret = vec![];
    // NB: declarations are already deduplicated, so we don't have to check for
    // it here.
    for &(ref declaration, _) in keyframe.block.read().declarations.iter() {
        if let Some(property) = TransitionProperty::from_declaration(declaration) {
            ret.push(property);
        }
    }

    ret
}

impl KeyframesAnimation {
    /// Create a keyframes animation from a given list of keyframes.
    ///
    /// This will return `None` if the list of keyframes is empty, or there are
    /// no animated properties obtained from the keyframes.
    ///
    /// Otherwise, this will compute and sort the steps used for the animation,
    /// and return the animation object.
    pub fn from_keyframes(keyframes: &[Arc<RwLock<Keyframe>>]) -> Option<Self> {
        if keyframes.is_empty() {
            return None;
        }

        let animated_properties = get_animated_properties(&keyframes[0].read());
        if animated_properties.is_empty() {
            return None;
        }

        let mut steps = vec![];

        for keyframe in keyframes {
            let keyframe = keyframe.read();
            for percentage in keyframe.selector.0.iter() {
                steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations {
                    block: keyframe.block.clone(),
                }));
            }
        }

        // Sort by the start percentage, so we can easily find a frame.
        steps.sort_by_key(|step| step.start_percentage);

        // Prepend autogenerated keyframes if appropriate.
        if steps[0].start_percentage.0 != 0. {
            steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.),
                                               KeyframesStepValue::ComputedValues));
        }

        if steps.last().unwrap().start_percentage.0 != 1. {
            steps.push(KeyframesStep::new(KeyframePercentage::new(1.),
                                          KeyframesStepValue::ComputedValues));
        }

        Some(KeyframesAnimation {
            steps: steps,
            properties_changed: animated_properties,
        })
    }
}

/// Parses a keyframes list, like:
/// 0%, 50% {
///     width: 50%;
/// }
///
/// 40%, 60%, 100% {
///     width: 100%;
/// }
struct KeyframeListParser<'a> {
    context: &'a ParserContext<'a>,
}

/// Parses a keyframe list from CSS input.
pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Vec<Arc<RwLock<Keyframe>>> {
    RuleListParser::new_for_nested_rule(input, KeyframeListParser { context: context })
        .filter_map(Result::ok)
        .collect()
}

enum Void {}
impl<'a> AtRuleParser for KeyframeListParser<'a> {
    type Prelude = Void;
    type AtRule = Arc<RwLock<Keyframe>>;
}

impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
    type Prelude = KeyframeSelector;
    type QualifiedRule = Arc<RwLock<Keyframe>>;

    fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> {
        let start = input.position();
        match KeyframeSelector::parse(input) {
            Ok(sel) => Ok(sel),
            Err(()) => {
                let message = format!("Invalid keyframe rule: '{}'", input.slice_from(start));
                log_css_error(input, start, &message, self.context);
                Err(())
            }
        }
    }

    fn parse_block(&mut self, prelude: Self::Prelude, input: &mut Parser)
                   -> Result<Self::QualifiedRule, ()> {
        let parser = KeyframeDeclarationParser {
            context: self.context,
            declarations: vec![],
        };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            match declaration {
                Ok(_) => (),
                Err(range) => {
                    let pos = range.start;
                    let message = format!("Unsupported keyframe property declaration: '{}'",
                                          iter.input.slice(range));
                    log_css_error(iter.input, pos, &*message, self.context);
                }
            }
            // `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
        }
        Ok(Arc::new(RwLock::new(Keyframe {
            selector: prelude,
            block: Arc::new(RwLock::new(PropertyDeclarationBlock {
                declarations: iter.parser.declarations,
                important_count: 0,
            })),
        })))
    }
}

struct KeyframeDeclarationParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
    declarations: Vec<(PropertyDeclaration, Importance)>
}

/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for KeyframeDeclarationParser<'a, 'b> {
    type Prelude = ();
    type AtRule = ();
}

impl<'a, 'b> DeclarationParser for KeyframeDeclarationParser<'a, 'b> {
    /// We parse rules directly into the declarations object
    type Declaration = ();

    fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
        let id = try!(PropertyId::parse(name.into()));
        let old_len = self.declarations.len();
        match PropertyDeclaration::parse(id, self.context, input, &mut self.declarations, true) {
            PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}
            _ => {
                self.declarations.truncate(old_len);
                return Err(());
            }
        }
        // In case there is still unparsed text in the declaration, we should roll back.
        if !input.is_exhausted() {
            self.declarations.truncate(old_len);
            Err(())
        } else {
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;

use sdl2::render::{Renderer, Texture};
use sdl2_image::LoadTexture;
use std::path::Path;
use std::collections::HashMap;

trait ImageLoader {
    type Image;
    fn load_from_path(&self, path: &Path) -> Result<Self::Image, String>;
}

impl<'a> ImageLoader for Renderer<'a> {
    type Image = Texture;
    fn load_from_path(&self, path: &Path) -> Result<Texture, String> {
        self.load_texture(path)
    }
}

struct ResourceManager<'a, I: ImageLoader> {
    texture_cache: HashMap<&'a str, I::Image>,
    image_loader: I,
}

impl<'a, I: ImageLoader> ResourceManager<'a, I> {
    pub fn new(image_loader: I) -> Self {
        ResourceManager {
            texture_cache: HashMap::new(),
            image_loader: image_loader,
        }
    }
    pub fn getTexture(&mut self, path: &'a str) -> Result<&I::Image, String> {
        if !self.texture_cache.contains_key(path) {
            let image_path = Path::new(path);
            let texture = try!(self.image_loader.load_from_path(image_path));
            self.texture_cache.insert(path, texture);
        }
        self.texture_cache.get(path).ok_or("Texture Cache Error: No such path".into())
    }
}

#[cfg(test)]
mod test {
    use std::path::Path;
    use sdl2::render::Texture;
    use std::cell::{RefCell, Ref};
    use super::ImageLoader;
    use super::ResourceManager;

    struct MockImage {
        pub path: String,
        pub id: u16,
    }

    struct MockImageLoader {
        pub load_count: RefCell<u16>,
        pub error: Option<String>,
    }

    impl ImageLoader for MockImageLoader {
        type Image = MockImage;

        fn load_from_path(&self, path: &Path) -> Result<MockImage, String> {
            *self.load_count.borrow_mut() += 1;
            match self.error {
                None => {
                    Ok(MockImage {
                        path: path.to_str().unwrap_or("").into(),
                        id: *self.load_count.borrow(),
                    })
                }
                Some(ref e) => Err(e.clone()),
            }
        }
    }

    #[test]
    fn loads_image() {
        let imageLoader = MockImageLoader {
            load_count: RefCell::new(0),
            error: None,
        };
        let mut subject = ResourceManager::new(imageLoader);
        let image = subject.getTexture("mypath/").unwrap();
        assert_eq!(image.path, String::from("mypath/"));
        assert_eq!(image.id, 1);
    }

    #[test]
    fn returns_error() {
        let imageLoader = MockImageLoader {
            load_count: RefCell::new(0),
            error: Some("FAIL".into()),
        };
        let mut subject = ResourceManager::new(imageLoader);
        let image = subject.getTexture("mypath/");
        assert_eq!(image.err(), Some("FAIL".into()));
    }

    #[test]
    fn caches_images() {
        let imageLoader = MockImageLoader {
            load_count: RefCell::new(0),
            error: None,
        };

        let mut subject = ResourceManager::new(imageLoader);

        {
            let image = subject.getTexture("mypath/1").unwrap();
            assert_eq!(image.path, String::from("mypath/1"));
            assert_eq!(image.id, 1);
        }

        // no error because image is already cached
        {
            let image = subject.getTexture("mypath/1").unwrap();
            assert_eq!(image.path, String::from("mypath/1"));
            assert_eq!(image.id, 1);
        }

        // no error because image is already cached
        let image = subject.getTexture("mypath/2").unwrap();
        assert_eq!(image.path, String::from("mypath/2"));
        assert_eq!(image.id, 2);
    }
}
<commit_msg>use refcell and rc to hide mutability from getTexture<commit_after>extern crate sdl2;

use sdl2::render::{Renderer, Texture};
use sdl2_image::LoadTexture;
use std::path::Path;
use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;

trait ImageLoader {
    type Image;
    fn load_from_path(&self, path: &Path) -> Result<Self::Image, String>;
}

impl<'a> ImageLoader for Renderer<'a> {
    type Image = Texture;
    fn load_from_path(&self, path: &Path) -> Result<Texture, String> {
        self.load_texture(path)
    }
}

struct ResourceManager<'a, I: ImageLoader> {
    texture_cache: RefCell<HashMap<&'a str, Rc<I::Image>>>,
    image_loader: I,
}

impl<'a, I: ImageLoader> ResourceManager<'a, I> {
    pub fn new(image_loader: I) -> Self {
        ResourceManager {
            texture_cache: RefCell::new(HashMap::new()),
            image_loader: image_loader,
        }
    }
    pub fn getTexture(&self, path: &'a str) -> Result<Rc<I::Image>, String> {
        {
            let cache = self.texture_cache.borrow();
            let image = cache.get(path);
            if let Some(x) = image {
                return Ok(x.clone());
            }
        }
        let mut cache = self.texture_cache.borrow_mut();
        let image_path = Path::new(path);
        let image = Rc::new(try!(self.image_loader.load_from_path(image_path)));
        cache.insert(path, image.clone());
        Ok(image.clone())
    }
}

#[cfg(test)]
mod test {
    use std::path::Path;
    use std::cell::RefCell;
    use super::ImageLoader;
    use super::ResourceManager;

    #[derive(Debug)]
    struct MockImage {
        pub path: String,
        pub id: u16,
    }

    struct MockImageLoader {
        pub load_count: RefCell<u16>,
        pub error: Option<String>,
    }

    impl ImageLoader for MockImageLoader {
        type Image = MockImage;

        fn load_from_path(&self, path: &Path) -> Result<MockImage, String> {
            *self.load_count.borrow_mut() += 1;
            match self.error {
                None => {
                    Ok(MockImage {
                        path: path.to_str().unwrap_or("").into(),
                        id: *self.load_count.borrow(),
                    })
                }
                Some(ref e) => Err(e.clone()),
            }
        }
    }

    #[test]
    fn loads_image() {
        let image_loader = MockImageLoader {
            load_count: RefCell::new(0),
            error: None,
        };
        let subject = ResourceManager::new(image_loader);
        let image = subject.getTexture("mypath/").unwrap();
        assert_eq!(image.path, String::from("mypath/"));
        assert_eq!(image.id, 1);
    }

    #[test]
    fn returns_error() {
        let image_loader = MockImageLoader {
            load_count: RefCell::new(0),
            error: Some("FAIL".into()),
        };
        let subject = ResourceManager::new(image_loader);
        let image = subject.getTexture("mypath/");
        assert_eq!(image.err(), Some("FAIL".into()));
    }

    #[test]
    fn caches_images() {
        let image_loader = MockImageLoader {
            load_count: RefCell::new(0),
            error: None,
        };
        let subject = ResourceManager::new(image_loader);

        // get a new image - ID will be 1
        let image1 = subject.getTexture("mypath/1").unwrap();
        assert_eq!(image1.path, String::from("mypath/1"));
        assert_eq!(image1.id, 1);

        // get the image again - ID should not change
        let image2 = subject.getTexture("mypath/1").unwrap();
        assert_eq!(image2.path, String::from("mypath/1"));
        assert_eq!(image2.id, 1);

        // get another time - ID should be a new one
        let image3 = subject.getTexture("mypath/2").unwrap();
        assert_eq!(image3.path, String::from("mypath/2"));
        assert_eq!(image3.id, 2);
    }
}
<|endoftext|>


<commit_before>// Self just needs to be a matrix.  Size and shape of Self do not matter.
pub trait Matrix<T> {
    type RowIndex;
    type ColIndex;
    type RowVector;
    type ColVector;

    fn add(&mut self, m: &Self) -> &mut Self;
    fn add_into(&self, m: &Self, dest: &mut Self);
    fn sub(&mut self, m: &Self) -> &mut Self;
    fn sub_into(&self, m: &Self, dest: &mut Self);
    fn get_column(&self, column: Self::ColIndex, dest: &mut Self::ColVector);
    fn get_row(&self, column: Self::RowIndex, dest: &mut Self::RowVector);
    // todo: add more here
}

// Self must be a Square Matrix, but these functions cannot depend upon the size of Self.
pub trait SquareMatrix<T>: Matrix<T> {
    fn determinant(&self) -> T;
    fn identity(&mut self) -> &mut Self;
    fn invert(&mut self) -> &mut Self;
    fn invert_into(&self, dest: &mut Self);
    // todo: add more here
}

pub enum Mat2Index {
    One,
    Two,
}

pub enum Mat3Index {
    One,
    Two,
    Three,
}

pub enum Mat4Index {
    One,
    Two,
    Three,
}

pub mod matrix3f;
<commit_msg>fix Mat index enums<commit_after>// Self just needs to be a matrix.  Size and shape of Self do not matter.
pub trait Matrix<T> {
    type RowIndex;
    type ColIndex;
    type RowVector;
    type ColVector;

    fn add(&mut self, m: &Self) -> &mut Self;
    fn add_into(&self, m: &Self, dest: &mut Self);
    fn sub(&mut self, m: &Self) -> &mut Self;
    fn sub_into(&self, m: &Self, dest: &mut Self);
    fn get_column(&self, column: Self::ColIndex, dest: &mut Self::ColVector);
    fn get_row(&self, column: Self::RowIndex, dest: &mut Self::RowVector);
    // todo: add more here
}

// Self must be a Square Matrix, but these functions cannot depend upon the size of Self.
pub trait SquareMatrix<T>: Matrix<T> {
    fn determinant(&self) -> T;
    fn identity(&mut self) -> &mut Self;
    fn invert(&mut self) -> &mut Self;
    fn invert_into(&self, dest: &mut Self);
    // todo: add more here
}

pub enum Mat2Index {
    Zero,
    One,
}

pub enum Mat3Index {
    Zero,
    One,
    Two,
}

pub enum Mat4Index {
    Zero,
    One,
    Two,
    Three,
}

pub mod matrix3f;
<|endoftext|>


<commit_before>// ignore-windows: Concurrency on Windows is not supported yet.
// compile-flags: -Zmiri-disable-isolation

use std::sync::mpsc::{channel, sync_channel};
use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
use std::thread;
use std::time::{Duration, Instant};

// Check if Rust barriers are working.

/// This test is taken from the Rust documentation.
fn check_barriers() {
    let mut handles = Vec::with_capacity(10);
    let barrier = Arc::new(Barrier::new(10));
    for _ in 0..10 {
        let c = barrier.clone();
        // The same messages will be printed together.
        // You will NOT see any interleaving.
        handles.push(thread::spawn(move || {
            println!("before wait");
            c.wait();
            println!("after wait");
        }));
    }
    // Wait for other threads to finish.
    for handle in handles {
        handle.join().unwrap();
    }
}

// Check if Rust conditional variables are working.

/// The test taken from the Rust documentation.
fn check_conditional_variables_notify_one() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = pair.clone();

    // Spawn a new thread.
    thread::spawn(move || {
        thread::yield_now();
        let (lock, cvar) = &*pair2;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    });

    // Wait for the thread to fully start up.
    let (lock, cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }
}

fn check_conditional_variables_notify_all() {
    let pair = Arc::new(((Mutex::new(())), Condvar::new()));

    // Spawn threads and block them on the conditional variable.
    let handles: Vec<_> = (0..5)
        .map(|_| {
            let pair2 = pair.clone();
            thread::spawn(move || {
                let (lock, cvar) = &*pair2;
                let guard = lock.lock().unwrap();
                // Block waiting on the conditional variable.
                let _ = cvar.wait(guard).unwrap();
            })
        })
        .inspect(|_| {
            thread::yield_now();
            thread::yield_now();
        })
        .collect();

    let (_, cvar) = &*pair;
    // Unblock all threads.
    cvar.notify_all();

    for handle in handles {
        handle.join().unwrap();
    }
}

/// Test that waiting on a conditional variable with a timeout does not
/// deadlock.
fn check_conditional_variables_timed_wait_timeout() {
    let lock = Mutex::new(());
    let cvar = Condvar::new();
    let guard = lock.lock().unwrap();
    let now = Instant::now();
    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
    assert!(timeout.timed_out());
    let elapsed_time = now.elapsed().as_millis();
    assert!(100 <= elapsed_time && elapsed_time <= 300);
}

/// Test that signaling a conditional variable when waiting with a timeout works
/// as expected.
fn check_conditional_variables_timed_wait_notimeout() {
    let pair = Arc::new((Mutex::new(()), Condvar::new()));
    let pair2 = pair.clone();

    let (lock, cvar) = &*pair;
    let guard = lock.lock().unwrap();

    let handle = thread::spawn(move || {
        let (_lock, cvar) = &*pair2;
        cvar.notify_one();
    });

    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(200)).unwrap();
    assert!(!timeout.timed_out());
    handle.join().unwrap();
}

// Check if locks are working.

fn check_mutex() {
    let data = Arc::new(Mutex::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.lock().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

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

    assert!(data.try_lock().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_write() {
    let data = Arc::new(RwLock::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.write().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

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

    assert!(data.try_write().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_read_no_deadlock() {
    let l1 = Arc::new(RwLock::new(0));
    let l2 = Arc::new(RwLock::new(0));

    let l1_copy = Arc::clone(&l1);
    let l2_copy = Arc::clone(&l2);
    let _guard1 = l1.read().unwrap();
    let handle = thread::spawn(move || {
        let _guard2 = l2_copy.read().unwrap();
        thread::yield_now();
        let _guard1 = l1_copy.read().unwrap();
    });
    thread::yield_now();
    let _guard2 = l2.read().unwrap();
    handle.join().unwrap();
}

// Check if channels are working.

/// The test taken from the Rust documentation.
fn simple_send() {
    let (tx, rx) = channel();
    thread::spawn(move || {
        tx.send(10).unwrap();
    });
    assert_eq!(rx.recv().unwrap(), 10);
}

/// The test taken from the Rust documentation.
fn multiple_send() {
    let (tx, rx) = channel();
    for i in 0..10 {
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(i).unwrap();
        });
    }

    let mut sum = 0;
    for _ in 0..10 {
        let j = rx.recv().unwrap();
        assert!(0 <= j && j < 10);
        sum += j;
    }
    assert_eq!(sum, 45);
}

/// The test taken from the Rust documentation.
fn send_on_sync() {
    let (sender, receiver) = sync_channel(1);

    // this returns immediately
    sender.send(1).unwrap();

    thread::spawn(move || {
        // this will block until the previous message has been received
        sender.send(2).unwrap();
    });

    assert_eq!(receiver.recv().unwrap(), 1);
    assert_eq!(receiver.recv().unwrap(), 2);
}

// Check if Rust once statics are working.

static mut VAL: usize = 0;
static INIT: Once = Once::new();

fn get_cached_val() -> usize {
    unsafe {
        INIT.call_once(|| {
            VAL = expensive_computation();
        });
        VAL
    }
}

fn expensive_computation() -> usize {
    let mut i = 1;
    let mut c = 1;
    while i < 1000 {
        i *= c;
        c += 1;
    }
    i
}

/// The test taken from the Rust documentation.
fn check_once() {
    let handles: Vec<_> = (0..10)
        .map(|_| {
            thread::spawn(|| {
                thread::yield_now();
                let val = get_cached_val();
                assert_eq!(val, 5040);
            })
        })
        .collect();
    for handle in handles {
        handle.join().unwrap();
    }
}

fn check_rwlock_unlock_bug1() {
    // There was a bug where when un-read-locking an rwlock that still has other
    // readers waiting, we'd accidentally also let a writer in.
    // That caused an ICE.
    let l = Arc::new(RwLock::new(0));

    let r1 = l.read().unwrap();
    let r2 = l.read().unwrap();

    // Make a waiting writer.
    let l2 = l.clone();
    thread::spawn(move || {
        let mut w = l2.write().unwrap();
        *w += 1;
    });
    thread::yield_now();

    drop(r1);
    assert_eq!(*r2, 0);
    thread::yield_now();
    thread::yield_now();
    thread::yield_now();
    assert_eq!(*r2, 0);
    drop(r2);
}

fn check_rwlock_unlock_bug2() {
    // There was a bug where when un-read-locking an rwlock by letting the last reader leaver,
    // we'd forget to wake up a writer.
    // That meant the writer thread could never run again.
    let l = Arc::new(RwLock::new(0));

    let r = l.read().unwrap();

    // Make a waiting writer.
    let l2 = l.clone();
    let h = thread::spawn(move || {
        let _w = l2.write().unwrap();
    });
    thread::yield_now();

    drop(r);
    h.join().unwrap();
}

fn park_timeout() {
    let start = Instant::now();

    thread::park_timeout(Duration::from_millis(200));
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn park_unpark() {
    let t1 = thread::current();
    let t2 = thread::spawn(move || {
        thread::park();
        thread::sleep(Duration::from_millis(200));
        t1.unpark();
    });

    let start = Instant::now();

    t2.thread().unpark();
    thread::park();
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn main() {
    check_barriers();
    check_conditional_variables_notify_one();
    check_conditional_variables_notify_all();
    check_conditional_variables_timed_wait_timeout();
    check_conditional_variables_timed_wait_notimeout();
    check_mutex();
    check_rwlock_write();
    check_rwlock_read_no_deadlock();
    simple_send();
    multiple_send();
    send_on_sync();
    check_once();
    check_rwlock_unlock_bug1();
    check_rwlock_unlock_bug2();
    park_timeout();
    park_unpark();
}
<commit_msg>increase timeout to avoid spurious test failures<commit_after>// ignore-windows: Concurrency on Windows is not supported yet.
// compile-flags: -Zmiri-disable-isolation

use std::sync::mpsc::{channel, sync_channel};
use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
use std::thread;
use std::time::{Duration, Instant};

// Check if Rust barriers are working.

/// This test is taken from the Rust documentation.
fn check_barriers() {
    let mut handles = Vec::with_capacity(10);
    let barrier = Arc::new(Barrier::new(10));
    for _ in 0..10 {
        let c = barrier.clone();
        // The same messages will be printed together.
        // You will NOT see any interleaving.
        handles.push(thread::spawn(move || {
            println!("before wait");
            c.wait();
            println!("after wait");
        }));
    }
    // Wait for other threads to finish.
    for handle in handles {
        handle.join().unwrap();
    }
}

// Check if Rust conditional variables are working.

/// The test taken from the Rust documentation.
fn check_conditional_variables_notify_one() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = pair.clone();

    // Spawn a new thread.
    thread::spawn(move || {
        thread::yield_now();
        let (lock, cvar) = &*pair2;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    });

    // Wait for the thread to fully start up.
    let (lock, cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }
}

fn check_conditional_variables_notify_all() {
    let pair = Arc::new(((Mutex::new(())), Condvar::new()));

    // Spawn threads and block them on the conditional variable.
    let handles: Vec<_> = (0..5)
        .map(|_| {
            let pair2 = pair.clone();
            thread::spawn(move || {
                let (lock, cvar) = &*pair2;
                let guard = lock.lock().unwrap();
                // Block waiting on the conditional variable.
                let _ = cvar.wait(guard).unwrap();
            })
        })
        .inspect(|_| {
            thread::yield_now();
            thread::yield_now();
        })
        .collect();

    let (_, cvar) = &*pair;
    // Unblock all threads.
    cvar.notify_all();

    for handle in handles {
        handle.join().unwrap();
    }
}

/// Test that waiting on a conditional variable with a timeout does not
/// deadlock.
fn check_conditional_variables_timed_wait_timeout() {
    let lock = Mutex::new(());
    let cvar = Condvar::new();
    let guard = lock.lock().unwrap();
    let now = Instant::now();
    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
    assert!(timeout.timed_out());
    let elapsed_time = now.elapsed().as_millis();
    assert!(100 <= elapsed_time && elapsed_time <= 300);
}

/// Test that signaling a conditional variable when waiting with a timeout works
/// as expected.
fn check_conditional_variables_timed_wait_notimeout() {
    let pair = Arc::new((Mutex::new(()), Condvar::new()));
    let pair2 = pair.clone();

    let (lock, cvar) = &*pair;
    let guard = lock.lock().unwrap();

    let handle = thread::spawn(move || {
        let (_lock, cvar) = &*pair2;
        cvar.notify_one();
    });

    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(500)).unwrap();
    assert!(!timeout.timed_out());
    handle.join().unwrap();
}

// Check if locks are working.

fn check_mutex() {
    let data = Arc::new(Mutex::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.lock().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

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

    assert!(data.try_lock().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_write() {
    let data = Arc::new(RwLock::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.write().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

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

    assert!(data.try_write().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_read_no_deadlock() {
    let l1 = Arc::new(RwLock::new(0));
    let l2 = Arc::new(RwLock::new(0));

    let l1_copy = Arc::clone(&l1);
    let l2_copy = Arc::clone(&l2);
    let _guard1 = l1.read().unwrap();
    let handle = thread::spawn(move || {
        let _guard2 = l2_copy.read().unwrap();
        thread::yield_now();
        let _guard1 = l1_copy.read().unwrap();
    });
    thread::yield_now();
    let _guard2 = l2.read().unwrap();
    handle.join().unwrap();
}

// Check if channels are working.

/// The test taken from the Rust documentation.
fn simple_send() {
    let (tx, rx) = channel();
    thread::spawn(move || {
        tx.send(10).unwrap();
    });
    assert_eq!(rx.recv().unwrap(), 10);
}

/// The test taken from the Rust documentation.
fn multiple_send() {
    let (tx, rx) = channel();
    for i in 0..10 {
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(i).unwrap();
        });
    }

    let mut sum = 0;
    for _ in 0..10 {
        let j = rx.recv().unwrap();
        assert!(0 <= j && j < 10);
        sum += j;
    }
    assert_eq!(sum, 45);
}

/// The test taken from the Rust documentation.
fn send_on_sync() {
    let (sender, receiver) = sync_channel(1);

    // this returns immediately
    sender.send(1).unwrap();

    thread::spawn(move || {
        // this will block until the previous message has been received
        sender.send(2).unwrap();
    });

    assert_eq!(receiver.recv().unwrap(), 1);
    assert_eq!(receiver.recv().unwrap(), 2);
}

// Check if Rust once statics are working.

static mut VAL: usize = 0;
static INIT: Once = Once::new();

fn get_cached_val() -> usize {
    unsafe {
        INIT.call_once(|| {
            VAL = expensive_computation();
        });
        VAL
    }
}

fn expensive_computation() -> usize {
    let mut i = 1;
    let mut c = 1;
    while i < 1000 {
        i *= c;
        c += 1;
    }
    i
}

/// The test taken from the Rust documentation.
fn check_once() {
    let handles: Vec<_> = (0..10)
        .map(|_| {
            thread::spawn(|| {
                thread::yield_now();
                let val = get_cached_val();
                assert_eq!(val, 5040);
            })
        })
        .collect();
    for handle in handles {
        handle.join().unwrap();
    }
}

fn check_rwlock_unlock_bug1() {
    // There was a bug where when un-read-locking an rwlock that still has other
    // readers waiting, we'd accidentally also let a writer in.
    // That caused an ICE.
    let l = Arc::new(RwLock::new(0));

    let r1 = l.read().unwrap();
    let r2 = l.read().unwrap();

    // Make a waiting writer.
    let l2 = l.clone();
    thread::spawn(move || {
        let mut w = l2.write().unwrap();
        *w += 1;
    });
    thread::yield_now();

    drop(r1);
    assert_eq!(*r2, 0);
    thread::yield_now();
    thread::yield_now();
    thread::yield_now();
    assert_eq!(*r2, 0);
    drop(r2);
}

fn check_rwlock_unlock_bug2() {
    // There was a bug where when un-read-locking an rwlock by letting the last reader leaver,
    // we'd forget to wake up a writer.
    // That meant the writer thread could never run again.
    let l = Arc::new(RwLock::new(0));

    let r = l.read().unwrap();

    // Make a waiting writer.
    let l2 = l.clone();
    let h = thread::spawn(move || {
        let _w = l2.write().unwrap();
    });
    thread::yield_now();

    drop(r);
    h.join().unwrap();
}

fn park_timeout() {
    let start = Instant::now();

    thread::park_timeout(Duration::from_millis(200));
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn park_unpark() {
    let t1 = thread::current();
    let t2 = thread::spawn(move || {
        thread::park();
        thread::sleep(Duration::from_millis(200));
        t1.unpark();
    });

    let start = Instant::now();

    t2.thread().unpark();
    thread::park();
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn main() {
    check_barriers();
    check_conditional_variables_notify_one();
    check_conditional_variables_notify_all();
    check_conditional_variables_timed_wait_timeout();
    check_conditional_variables_timed_wait_notimeout();
    check_mutex();
    check_rwlock_write();
    check_rwlock_read_no_deadlock();
    simple_send();
    multiple_send();
    send_on_sync();
    check_once();
    check_rwlock_unlock_bug1();
    check_rwlock_unlock_bug2();
    park_timeout();
    park_unpark();
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

#[repr(C)]
struct MemoryMapTag {
	tag_type: u32,
	size: u32,
	entry_size: u32,
	/// This is currently set to `0`.
	entry_version: u32,
	first_entry: MemoryMapEntry
}

#[derive(Debug)]
#[repr(C, packed)]
struct MemoryMapEntry {
	/// The starting physical address
	base_addr: u64,
	/// The size of the memory region, in bytes.
	length: u64,
	/// The type of memory region contained.
	entry_type: u32,
	/// This should be set to `0` and ignored by the bootloader.
	reserved: u32
}

#[derive(Debug, PartialEq, Eq)]
enum MemoryType {
	Usable         = 1,
	UsableWithACPI = 3,
	Unusable       = 4,
}

impl MemoryMapEntry {
	fn base_address(&self) -> u64 {
		self.base_addr
	}

	fn length(&self) -> u64 {
		self.length
	}

	fn memory_type(&self) -> MemoryType {
		match self.entry_type {
			1 => MemoryType::Usable,
			3 => MemoryType::UsableWithACPI,
			_ => MemoryType::Unusable
		}
	}

	fn is_usable_region(&self) -> bool {
		self.memory_type() == MemoryType::Usable
	}
}

struct MemoryMapIter {
	current_entry: *const MemoryMapEntry,
	final_entry: *const MemoryMapEntry,
	// We need to know the entry size so we can calculate the
	// address of the next memory map entry.
	entry_size: u32,
}

impl MemoryMapIter {
	fn new(current_entry: *const MemoryMapEntry,
		   final_entry: *const MemoryMapEntry,
		   entry_size: u32) -> MemoryMapIter
	{
		MemoryMapIter {
			current_entry: current_entry,
			final_entry: final_entry,
			entry_size: entry_size,
		}
	}
}

impl Iterator for MemoryMapIter {
	type Item = &'static MemoryMapEntry;

	fn next(&mut self) -> Option<Self::Item> {
		// Loop until the next usable memory region. We ignore the unusable regions
		// per the Multiboot2 standard requirements.
		loop {
			if self.current_entry <= self.final_entry {
				let current_entry = unsafe { &*self.current_entry };
				let next_entry = (self.current_entry as u64) + (self.entry_size as u64);

				self.current_entry = next_entry as *const MemoryMapEntry;

				if current_entry.is_usable_region() {
					return Some(current_entry);
				}

			} else {
				// We have fallen off the end of the memory map.
				return None;
			}
		}
	}
}<commit_msg>We can now construct and iterate over memory maps.<commit_after>#![allow(dead_code)]
use tag::TagType;

#[repr(C)]
struct MemoryMapTag {
	tag_type: u32,
	size: u32,
	entry_size: u32,
	/// This is currently set to `0`.
	entry_version: u32,
	first_entry: MemoryMapEntry
}

impl MemoryMapTag {
	fn memory_map(&self) -> MemoryMapIter {
		let ptr = self as *const MemoryMapTag;
		let first_entry = (&self.first_entry) as *const MemoryMapEntry;
		let final_entry = ((ptr as u64) + (self.size as u64)) as *const MemoryMapEntry;

		MemoryMapIter::new(first_entry, final_entry, self.entry_size)
	}

	fn is_valid(&self) -> bool {
		self.tag_type == TagType::MemoryMap as u32
	}
}

#[derive(Debug)]
#[repr(C, packed)]
struct MemoryMapEntry {
	/// The starting physical address
	base_addr: u64,
	/// The size of the memory region, in bytes.
	length: u64,
	/// The type of memory region contained.
	entry_type: u32,
	/// This should be set to `0` and ignored by the bootloader.
	reserved: u32
}

#[derive(Debug, PartialEq, Eq)]
enum MemoryType {
	Usable         = 1,
	UsableWithACPI = 3,
	Unusable       = 4,
}

impl MemoryMapEntry {
	fn base_address(&self) -> u64 {
		self.base_addr
	}

	fn length(&self) -> u64 {
		self.length
	}

	fn memory_type(&self) -> MemoryType {
		match self.entry_type {
			1 => MemoryType::Usable,
			3 => MemoryType::UsableWithACPI,
			_ => MemoryType::Unusable
		}
	}

	fn is_usable_region(&self) -> bool {
		self.memory_type() == MemoryType::Usable
	}
}

struct MemoryMapIter {
	current_entry: *const MemoryMapEntry,
	final_entry: *const MemoryMapEntry,
	// We need to know the entry size so we can calculate the
	// address of the next memory map entry.
	entry_size: u32,
}

impl MemoryMapIter {
	fn new(current_entry: *const MemoryMapEntry,
		   final_entry: *const MemoryMapEntry,
		   entry_size: u32) -> MemoryMapIter
	{
		MemoryMapIter {
			current_entry: current_entry,
			final_entry: final_entry,
			entry_size: entry_size,
		}
	}
}

impl Iterator for MemoryMapIter {
	type Item = &'static MemoryMapEntry;

	fn next(&mut self) -> Option<Self::Item> {
		// Loop until the next usable memory region. We ignore the unusable regions
		// per the Multiboot2 standard requirements.
		loop {
			if self.current_entry <= self.final_entry {
				let current_entry = unsafe { &*self.current_entry };
				let next_entry = (self.current_entry as u64) + (self.entry_size as u64);

				self.current_entry = next_entry as *const MemoryMapEntry;

				if current_entry.is_usable_region() {
					return Some(current_entry);
				}

			} else {
				// We have fallen off the end of the memory map.
				return None;
			}
		}
	}
}<|endoftext|>