<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/. */

//! Generic implementations of some DOM APIs so they can be shared between Servo
//! and Gecko.

use context::QuirksMode;
use dom::{TDocument, TElement, TNode};
use invalidation::element::invalidator::{Invalidation, InvalidationProcessor, InvalidationVector};
use selectors::{Element, NthIndexCache, SelectorList};
use selectors::matching::{self, MatchingContext, MatchingMode};
use selectors::parser::{Component, LocalName};
use smallvec::SmallVec;
use std::borrow::Borrow;

/// <https://dom.spec.whatwg.org/#dom-element-matches>
pub fn element_matches<E>(
    element: &E,
    selector_list: &SelectorList<E::Impl>,
    quirks_mode: QuirksMode,
) -> bool
where
    E: Element,
{
    let mut context = MatchingContext::new(
        MatchingMode::Normal,
        None,
        None,
        quirks_mode,
    );
    context.scope_element = Some(element.opaque());
    matching::matches_selector_list(selector_list, element, &mut context)
}

/// <https://dom.spec.whatwg.org/#dom-element-closest>
pub fn element_closest<E>(
    element: E,
    selector_list: &SelectorList<E::Impl>,
    quirks_mode: QuirksMode,
) -> Option<E>
where
    E: Element,
{
    let mut nth_index_cache = NthIndexCache::default();

    let mut context = MatchingContext::new(
        MatchingMode::Normal,
        None,
        Some(&mut nth_index_cache),
        quirks_mode,
    );
    context.scope_element = Some(element.opaque());

    let mut current = Some(element);
    while let Some(element) = current.take() {
        if matching::matches_selector_list(selector_list, &element, &mut context) {
            return Some(element);
        }
        current = element.parent_element();
    }

    return None;
}

/// A selector query abstraction, in order to be generic over QuerySelector and
/// QuerySelectorAll.
pub trait SelectorQuery<E: TElement> {
    /// The output of the query.
    type Output;

    /// Whether the query should stop after the first element has been matched.
    fn should_stop_after_first_match() -> bool;

    /// Append an element matching after the first query.
    fn append_element(output: &mut Self::Output, element: E);

    /// Returns true if the output is empty.
    fn is_empty(output: &Self::Output) -> bool;
}

/// The result of a querySelectorAll call.
pub type QuerySelectorAllResult<E> = SmallVec<[E; 128]>;

/// A query for all the elements in a subtree.
pub struct QueryAll;

impl<E: TElement> SelectorQuery<E> for QueryAll {
    type Output = QuerySelectorAllResult<E>;

    fn should_stop_after_first_match() -> bool { false }

    fn append_element(output: &mut Self::Output, element: E) {
        output.push(element);
    }

    fn is_empty(output: &Self::Output) -> bool {
        output.is_empty()
    }
}

/// A query for the first in-tree match of all the elements in a subtree.
pub struct QueryFirst;

impl<E: TElement> SelectorQuery<E> for QueryFirst {
    type Output = Option<E>;

    fn should_stop_after_first_match() -> bool { true }

    fn append_element(output: &mut Self::Output, element: E) {
        if output.is_none() {
            *output = Some(element)
        }
    }

    fn is_empty(output: &Self::Output) -> bool {
        output.is_none()
    }
}

struct QuerySelectorProcessor<'a, E, Q>
where
    E: TElement + 'a,
    Q: SelectorQuery<E>,
    Q::Output: 'a,
{
    results: &'a mut Q::Output,
    matching_context: MatchingContext<'a, E::Impl>,
    selector_list: &'a SelectorList<E::Impl>,
}

impl<'a, E, Q> InvalidationProcessor<'a, E> for QuerySelectorProcessor<'a, E, Q>
where
    E: TElement + 'a,
    Q: SelectorQuery<E>,
    Q::Output: 'a,
{
    fn light_tree_only(&self) -> bool { true }

    fn collect_invalidations(
        &mut self,
        element: E,
        self_invalidations: &mut InvalidationVector<'a>,
        descendant_invalidations: &mut InvalidationVector<'a>,
        _sibling_invalidations: &mut InvalidationVector<'a>,
    ) -> bool {
        // TODO(emilio): If the element is not a root element, and
        // selector_list has any descendant combinator, we need to do extra work
        // in order to handle properly things like:
        //
        //

        //

        //

        //

        //

        //
        // b.querySelector('#a div'); // Should return "c".
        //
        // For now, assert it's a root element.
        debug_assert!(element.parent_element().is_none());

        let target_vector =
            if self.matching_context.scope_element.is_some() {
                descendant_invalidations
            } else {
                self_invalidations
            };

        for selector in self.selector_list.0.iter() {
            target_vector.push(Invalidation::new(selector, 0))
        }

        false
    }

    fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl> {
        &mut self.matching_context
    }

    fn should_process_descendants(&mut self, _: E) -> bool {
        if Q::should_stop_after_first_match() {
            return Q::is_empty(&self.results)
        }

        true
    }

    fn invalidated_self(&mut self, e: E) {
        Q::append_element(self.results, e);
    }

    fn recursion_limit_exceeded(&mut self, _e: E) {}
    fn invalidated_descendants(&mut self, _e: E, _child: E) {}
}

fn collect_all_elements<E, Q, F>(
    root: E::ConcreteNode,
    results: &mut Q::Output,
    mut filter: F,
)
where
    E: TElement,
    Q: SelectorQuery<E>,
    F: FnMut(E) -> bool,
{
    for node in root.dom_descendants() {
        let element = match node.as_element() {
            Some(e) => e,
            None => continue,
        };

        if !filter(element) {
            continue;
        }

        Q::append_element(results, element);
        if Q::should_stop_after_first_match() {
            return;
        }
    }
}

/// Fast paths for querySelector with a single simple selector.
fn query_selector_single_query<E, Q>(
    root: E::ConcreteNode,
    component: &Component<E::Impl>,
    results: &mut Q::Output,
    quirks_mode: QuirksMode,
) -> Result<(), ()>
where
    E: TElement,
    Q: SelectorQuery<E>,
{
    match *component {
        Component::ExplicitUniversalType => {
            collect_all_elements::<E, Q, _>(root, results, |_| true)
        }
        Component::ID(ref id) => {
            // TODO(emilio): We may want to reuse Gecko's document ID table.
            let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
            collect_all_elements::<E, Q, _>(root, results, |element| {
                element.has_id(id, case_sensitivity)
            })
        }
        Component::Class(ref class) => {
            let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
            collect_all_elements::<E, Q, _>(root, results, |element| {
                element.has_class(class, case_sensitivity)
            })
        }
        Component::LocalName(LocalName { ref name, ref lower_name }) => {
            collect_all_elements::<E, Q, _>(root, results, |element| {
                if element.is_html_element_in_html_document() {
                    element.get_local_name() == lower_name.borrow()
                } else {
                    element.get_local_name() == name.borrow()
                }
            })
        }
        // TODO(emilio): More fast paths?
        _ => {
            return Err(())
        }
    }

    Ok(())
}

/// Fast paths for a given selector query.
///
/// FIXME(emilio, nbp): This may very well be a good candidate for code to be
/// replaced by HolyJit :)
fn query_selector_fast<E, Q>(
    root: E::ConcreteNode,
    selector_list: &SelectorList<E::Impl>,
    results: &mut Q::Output,
    quirks_mode: QuirksMode,
) -> Result<(), ()>
where
    E: TElement,
    Q: SelectorQuery<E>,
{
    // We need to return elements in document order, and reordering them
    // afterwards is kinda silly.
    if selector_list.0.len() > 1 {
        return Err(());
    }

    let selector = &selector_list.0[0];

    // Let's just care about the easy cases for now.
    if selector.len() == 1 {
        return query_selector_single_query::<E, Q>(
            root,
            selector.iter().next().unwrap(),
            results,
            quirks_mode,
        );
    }

    // FIXME(emilio): Implement better optimizations for compound selectors and
    // such.
    Err(())
}

// Slow path for a given selector query.
fn query_selector_slow<E, Q>(
    root: E::ConcreteNode,
    selector_list: &SelectorList<E::Impl>,
    results: &mut Q::Output,
    matching_context: &mut MatchingContext<E::Impl>,
)
where
    E: TElement,
    Q: SelectorQuery<E>,
{
    collect_all_elements::<E, Q, _>(root, results, |element| {
        matching::matches_selector_list(selector_list, &element, matching_context)
    });
}

/// <https://dom.spec.whatwg.org/#dom-parentnode-queryselector>
pub fn query_selector<E, Q>(
    root: E::ConcreteNode,
    selector_list: &SelectorList<E::Impl>,
    results: &mut Q::Output,
)
where
    E: TElement,
    Q: SelectorQuery<E>,
{
    use invalidation::element::invalidator::TreeStyleInvalidator;

    let quirks_mode = root.owner_doc().quirks_mode();
    let fast_result = query_selector_fast::<E, Q>(
        root,
        selector_list,
        results,
        quirks_mode,
    );

    if fast_result.is_ok() {
        return;
    }

    // Slow path: Use the invalidation machinery if we're a root, and tree
    // traversal otherwise.
    //
    // See the comment in collect_invalidations to see why only if we're a root.
    let mut nth_index_cache = NthIndexCache::default();
    let mut matching_context = MatchingContext::new(
        MatchingMode::Normal,
        None,
        Some(&mut nth_index_cache),
        quirks_mode,
    );

    let root_element = root.as_element();
    matching_context.scope_element = root_element.map(|e| e.opaque());

    // The invalidation mechanism is only useful in presence of combinators.
    //
    // We could do that check properly here, though checking the length of the
    // selectors is a good heuristic.
    let invalidation_may_be_useful =
        selector_list.0.iter().any(|s| s.len() > 1);

    if root_element.is_some() || !invalidation_may_be_useful {
        query_selector_slow::<E, Q>(
            root,
            selector_list,
            results,
            &mut matching_context,
        );
    } else {
        let mut processor = QuerySelectorProcessor::<E, Q> {
            results,
            matching_context,
            selector_list,
        };

        for node in root.dom_children() {
            if let Some(e) = node.as_element() {
                TreeStyleInvalidator::new(
                    e,
                    /* stack_limit_checker = */ None,
                    &mut processor,
                ).invalidate();
            }
        }
    }
}
<commit_msg>style: Add a fast path for querySelector/All with a single id selector using the doc ID table.<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/. */

//! Generic implementations of some DOM APIs so they can be shared between Servo
//! and Gecko.

use context::QuirksMode;
use dom::{TDocument, TElement, TNode};
use invalidation::element::invalidator::{Invalidation, InvalidationProcessor, InvalidationVector};
use selectors::{Element, NthIndexCache, SelectorList};
use selectors::attr::CaseSensitivity;
use selectors::matching::{self, MatchingContext, MatchingMode};
use selectors::parser::{Component, LocalName};
use smallvec::SmallVec;
use std::borrow::Borrow;

/// <https://dom.spec.whatwg.org/#dom-element-matches>
pub fn element_matches<E>(
    element: &E,
    selector_list: &SelectorList<E::Impl>,
    quirks_mode: QuirksMode,
) -> bool
where
    E: Element,
{
    let mut context = MatchingContext::new(
        MatchingMode::Normal,
        None,
        None,
        quirks_mode,
    );
    context.scope_element = Some(element.opaque());
    matching::matches_selector_list(selector_list, element, &mut context)
}

/// <https://dom.spec.whatwg.org/#dom-element-closest>
pub fn element_closest<E>(
    element: E,
    selector_list: &SelectorList<E::Impl>,
    quirks_mode: QuirksMode,
) -> Option<E>
where
    E: Element,
{
    let mut nth_index_cache = NthIndexCache::default();

    let mut context = MatchingContext::new(
        MatchingMode::Normal,
        None,
        Some(&mut nth_index_cache),
        quirks_mode,
    );
    context.scope_element = Some(element.opaque());

    let mut current = Some(element);
    while let Some(element) = current.take() {
        if matching::matches_selector_list(selector_list, &element, &mut context) {
            return Some(element);
        }
        current = element.parent_element();
    }

    return None;
}

/// A selector query abstraction, in order to be generic over QuerySelector and
/// QuerySelectorAll.
pub trait SelectorQuery<E: TElement> {
    /// The output of the query.
    type Output;

    /// Whether the query should stop after the first element has been matched.
    fn should_stop_after_first_match() -> bool;

    /// Append an element matching after the first query.
    fn append_element(output: &mut Self::Output, element: E);

    /// Returns true if the output is empty.
    fn is_empty(output: &Self::Output) -> bool;
}

/// The result of a querySelectorAll call.
pub type QuerySelectorAllResult<E> = SmallVec<[E; 128]>;

/// A query for all the elements in a subtree.
pub struct QueryAll;

impl<E: TElement> SelectorQuery<E> for QueryAll {
    type Output = QuerySelectorAllResult<E>;

    fn should_stop_after_first_match() -> bool { false }

    fn append_element(output: &mut Self::Output, element: E) {
        output.push(element);
    }

    fn is_empty(output: &Self::Output) -> bool {
        output.is_empty()
    }
}

/// A query for the first in-tree match of all the elements in a subtree.
pub struct QueryFirst;

impl<E: TElement> SelectorQuery<E> for QueryFirst {
    type Output = Option<E>;

    fn should_stop_after_first_match() -> bool { true }

    fn append_element(output: &mut Self::Output, element: E) {
        if output.is_none() {
            *output = Some(element)
        }
    }

    fn is_empty(output: &Self::Output) -> bool {
        output.is_none()
    }
}

struct QuerySelectorProcessor<'a, E, Q>
where
    E: TElement + 'a,
    Q: SelectorQuery<E>,
    Q::Output: 'a,
{
    results: &'a mut Q::Output,
    matching_context: MatchingContext<'a, E::Impl>,
    selector_list: &'a SelectorList<E::Impl>,
}

impl<'a, E, Q> InvalidationProcessor<'a, E> for QuerySelectorProcessor<'a, E, Q>
where
    E: TElement + 'a,
    Q: SelectorQuery<E>,
    Q::Output: 'a,
{
    fn light_tree_only(&self) -> bool { true }

    fn collect_invalidations(
        &mut self,
        element: E,
        self_invalidations: &mut InvalidationVector<'a>,
        descendant_invalidations: &mut InvalidationVector<'a>,
        _sibling_invalidations: &mut InvalidationVector<'a>,
    ) -> bool {
        // TODO(emilio): If the element is not a root element, and
        // selector_list has any descendant combinator, we need to do extra work
        // in order to handle properly things like:
        //
        //

        //

        //

        //

        //

        //
        // b.querySelector('#a div'); // Should return "c".
        //
        // For now, assert it's a root element.
        debug_assert!(element.parent_element().is_none());

        let target_vector =
            if self.matching_context.scope_element.is_some() {
                descendant_invalidations
            } else {
                self_invalidations
            };

        for selector in self.selector_list.0.iter() {
            target_vector.push(Invalidation::new(selector, 0))
        }

        false
    }

    fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl> {
        &mut self.matching_context
    }

    fn should_process_descendants(&mut self, _: E) -> bool {
        if Q::should_stop_after_first_match() {
            return Q::is_empty(&self.results)
        }

        true
    }

    fn invalidated_self(&mut self, e: E) {
        Q::append_element(self.results, e);
    }

    fn recursion_limit_exceeded(&mut self, _e: E) {}
    fn invalidated_descendants(&mut self, _e: E, _child: E) {}
}

fn collect_all_elements<E, Q, F>(
    root: E::ConcreteNode,
    results: &mut Q::Output,
    mut filter: F,
)
where
    E: TElement,
    Q: SelectorQuery<E>,
    F: FnMut(E) -> bool,
{
    for node in root.dom_descendants() {
        let element = match node.as_element() {
            Some(e) => e,
            None => continue,
        };

        if !filter(element) {
            continue;
        }

        Q::append_element(results, element);
        if Q::should_stop_after_first_match() {
            return;
        }
    }
}

/// Returns whether a given element is descendant of a given `root` node.
///
/// NOTE(emilio): if root == element, this returns false.
fn element_is_descendant_of<E>(element: E, root: E::ConcreteNode) -> bool
where
    E: TElement,
{
    let mut current = element.as_node().parent_node();
    while let Some(n) = current.take() {
        if n == root {
            return true;
        }

        current = n.parent_node();
    }
    false
}

/// Fast paths for querySelector with a single simple selector.
fn query_selector_single_query<E, Q>(
    root: E::ConcreteNode,
    component: &Component<E::Impl>,
    results: &mut Q::Output,
    quirks_mode: QuirksMode,
) -> Result<(), ()>
where
    E: TElement,
    Q: SelectorQuery<E>,
{
    match *component {
        Component::ExplicitUniversalType => {
            collect_all_elements::<E, Q, _>(root, results, |_| true)
        }
        Component::ID(ref id) => {
            let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();

            if case_sensitivity == CaseSensitivity::CaseSensitive &&
               root.is_in_document()
            {
                let doc = root.owner_doc();
                if let Ok(elements) = doc.elements_with_id(id) {
                    if root == doc.as_node() {
                        for element in elements {
                            Q::append_element(results, *element);
                            if Q::should_stop_after_first_match() {
                                break;
                            }
                        }
                    } else {
                        for element in elements {
                            if !element_is_descendant_of(*element, root) {
                                continue;
                            }

                            Q::append_element(results, *element);
                            if Q::should_stop_after_first_match() {
                                break;
                            }
                        }
                    }
                    return Ok(())
                }
            }

            collect_all_elements::<E, Q, _>(root, results, |element| {
                element.has_id(id, case_sensitivity)
            })
        }
        Component::Class(ref class) => {
            let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
            collect_all_elements::<E, Q, _>(root, results, |element| {
                element.has_class(class, case_sensitivity)
            })
        }
        Component::LocalName(LocalName { ref name, ref lower_name }) => {
            collect_all_elements::<E, Q, _>(root, results, |element| {
                if element.is_html_element_in_html_document() {
                    element.get_local_name() == lower_name.borrow()
                } else {
                    element.get_local_name() == name.borrow()
                }
            })
        }
        // TODO(emilio): More fast paths?
        _ => {
            return Err(())
        }
    }

    Ok(())
}

/// Fast paths for a given selector query.
///
/// FIXME(emilio, nbp): This may very well be a good candidate for code to be
/// replaced by HolyJit :)
fn query_selector_fast<E, Q>(
    root: E::ConcreteNode,
    selector_list: &SelectorList<E::Impl>,
    results: &mut Q::Output,
    quirks_mode: QuirksMode,
) -> Result<(), ()>
where
    E: TElement,
    Q: SelectorQuery<E>,
{
    // We need to return elements in document order, and reordering them
    // afterwards is kinda silly.
    if selector_list.0.len() > 1 {
        return Err(());
    }

    let selector = &selector_list.0[0];

    // Let's just care about the easy cases for now.
    if selector.len() == 1 {
        return query_selector_single_query::<E, Q>(
            root,
            selector.iter().next().unwrap(),
            results,
            quirks_mode,
        );
    }

    // FIXME(emilio): Implement better optimizations for compound selectors and
    // such.
    Err(())
}

// Slow path for a given selector query.
fn query_selector_slow<E, Q>(
    root: E::ConcreteNode,
    selector_list: &SelectorList<E::Impl>,
    results: &mut Q::Output,
    matching_context: &mut MatchingContext<E::Impl>,
)
where
    E: TElement,
    Q: SelectorQuery<E>,
{
    collect_all_elements::<E, Q, _>(root, results, |element| {
        matching::matches_selector_list(selector_list, &element, matching_context)
    });
}

/// <https://dom.spec.whatwg.org/#dom-parentnode-queryselector>
pub fn query_selector<E, Q>(
    root: E::ConcreteNode,
    selector_list: &SelectorList<E::Impl>,
    results: &mut Q::Output,
)
where
    E: TElement,
    Q: SelectorQuery<E>,
{
    use invalidation::element::invalidator::TreeStyleInvalidator;

    let quirks_mode = root.owner_doc().quirks_mode();
    let fast_result = query_selector_fast::<E, Q>(
        root,
        selector_list,
        results,
        quirks_mode,
    );

    if fast_result.is_ok() {
        return;
    }

    // Slow path: Use the invalidation machinery if we're a root, and tree
    // traversal otherwise.
    //
    // See the comment in collect_invalidations to see why only if we're a root.
    let mut nth_index_cache = NthIndexCache::default();
    let mut matching_context = MatchingContext::new(
        MatchingMode::Normal,
        None,
        Some(&mut nth_index_cache),
        quirks_mode,
    );

    let root_element = root.as_element();
    matching_context.scope_element = root_element.map(|e| e.opaque());

    // The invalidation mechanism is only useful in presence of combinators.
    //
    // We could do that check properly here, though checking the length of the
    // selectors is a good heuristic.
    let invalidation_may_be_useful =
        selector_list.0.iter().any(|s| s.len() > 1);

    if root_element.is_some() || !invalidation_may_be_useful {
        query_selector_slow::<E, Q>(
            root,
            selector_list,
            results,
            &mut matching_context,
        );
    } else {
        let mut processor = QuerySelectorProcessor::<E, Q> {
            results,
            matching_context,
            selector_list,
        };

        for node in root.dom_children() {
            if let Some(e) = node.as_element() {
                TreeStyleInvalidator::new(
                    e,
                    /* stack_limit_checker = */ None,
                    &mut processor,
                ).invalidate();
            }
        }
    }
}
<|endoftext|>


<commit_before>use bifrost::utils::fut_exec::wait;
use ram::cell::{Cell, CellHeader, ReadError, WriteError};
use ram::types::{Id, Value};
use server::transactions::TxnId;
use server::transactions::*;
use std::cell::Cell as StdCell;
use std::io;
use std::sync::Arc;

use bifrost::rpc::RPCError;
use futures::Future;

#[derive(Debug)]
pub enum TxnError {
    CannotFindAServer,
    IoError(io::Error),
    CannotBegin,
    NotRealizable,
    TooManyRetry,
    InternalError,
    Aborted(Option<Vec<RollbackFailure>>),
    RPCError(RPCError),
    ManagerError(TMError),
    ReadError(ReadError),
    WriteError(WriteError),
    PrepareError(TMPrepareResult),
    CommitError(EndResult),
    AbortError(AbortResult),
}

pub struct Transaction {
    pub tid: TxnId,
    pub state: StdCell<TxnState>,
    pub client: Arc<manager::AsyncServiceClient>,
}

impl Transaction {
    pub fn read(&self, id: Id) -> Result<Option<Cell>, TxnError> {
        match wait(self.client.read(self.tid.to_owned(), id)) {
            Ok(Ok(TxnExecResult::Accepted(cell))) => Ok(Some(cell)),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(ReadError::CellDoesNotExisted))) => Ok(None),
            Ok(Ok(TxnExecResult::Error(re))) => Err(TxnError::ReadError(re)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn read_selected(&self, id: Id, fields: Vec<u64>) -> Result<Option<Vec<Value>>, TxnError> {
        match wait(self.client.read_selected(self.tid.to_owned(), id, fields)) {
            Ok(Ok(TxnExecResult::Accepted(fields))) => Ok(Some(fields)),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(ReadError::CellDoesNotExisted))) => Ok(None),
            Ok(Ok(TxnExecResult::Error(re))) => Err(TxnError::ReadError(re)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn write(&self, cell: Cell) -> Result<(), TxnError> {
        match wait(self.client.write(self.tid.to_owned(), cell)) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn update(&self, cell: Cell) -> Result<(), TxnError> {
        match wait(self.client.update(self.tid.to_owned(), cell)) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn remove(&self, id: Id) -> Result<(), TxnError> {
        match wait(self.client.remove(self.tid.to_owned(), id)) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn head(&self, id: Id) -> Result<Option<CellHeader>, TxnError> {
        match wait(self.client.head(self.tid.to_owned(), id)) {
            Ok(Ok(TxnExecResult::Accepted(head))) => Ok(Some(head)),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(ReadError::CellDoesNotExisted))) => Ok(None),
            Ok(Ok(TxnExecResult::Error(re))) => Err(TxnError::ReadError(re)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn upsert(&self, cell: Cell) -> Result<(), TxnError> {
        match self.head(cell.id()) {
            Ok(Some(_)) => self.update(cell),
            Ok(None) => self.write(cell),
            Err(e) => Err(e),
        }
    }
    pub fn prepare(&self) -> Result<(), TxnError> {
        self.state.set(TxnState::Prepared);
        match wait(self.client.prepare(self.tid.to_owned())) {
            Ok(Ok(TMPrepareResult::Success)) => return Ok(()),
            Ok(Ok(TMPrepareResult::DMPrepareError(DMPrepareResult::NotRealizable))) => {
                Err(TxnError::NotRealizable)
            }
            Ok(Ok(TMPrepareResult::DMCommitError(DMCommitResult::CellChanged(_)))) => {
                Err(TxnError::NotRealizable)
            }
            Ok(Ok(rpr)) => Err(TxnError::PrepareError(rpr)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn commit(&self) -> Result<(), TxnError> {
        self.state.set(TxnState::Committed);
        match wait(self.client.commit(self.tid.to_owned())) {
            Ok(Ok(EndResult::Success)) => return Ok(()),
            Ok(Ok(EndResult::SomeLocksNotReleased)) => return Ok(()),
            Ok(Ok(er)) => Err(TxnError::CommitError(er)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn abort(&self) -> Result<(), TxnError> {
        if self.state.get() == TxnState::Aborted {
            return Ok(());
        }
        self.state.set(TxnState::Aborted);
        match wait(self.client.abort(self.tid.to_owned())) {
            Ok(Ok(AbortResult::Success(rollback_failures))) => {
                Err(TxnError::Aborted(rollback_failures))
            }
            Ok(Ok(ar)) => Err(TxnError::AbortError(ar)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
}
<commit_msg>wait at local thread<commit_after>use bifrost::utils::fut_exec::wait;
use ram::cell::{Cell, CellHeader, ReadError, WriteError};
use ram::types::{Id, Value};
use server::transactions::TxnId;
use server::transactions::*;
use std::cell::Cell as StdCell;
use std::io;
use std::sync::Arc;

use bifrost::rpc::RPCError;
use futures::Future;

#[derive(Debug)]
pub enum TxnError {
    CannotFindAServer,
    IoError(io::Error),
    CannotBegin,
    NotRealizable,
    TooManyRetry,
    InternalError,
    Aborted(Option<Vec<RollbackFailure>>),
    RPCError(RPCError),
    ManagerError(TMError),
    ReadError(ReadError),
    WriteError(WriteError),
    PrepareError(TMPrepareResult),
    CommitError(EndResult),
    AbortError(AbortResult),
}

pub struct Transaction {
    pub tid: TxnId,
    pub state: StdCell<TxnState>,
    pub client: Arc<manager::AsyncServiceClient>,
}

impl Transaction {
    pub fn read(&self, id: Id) -> Result<Option<Cell>, TxnError> {
        match self.client.read(self.tid.to_owned(), id).wait() {
            Ok(Ok(TxnExecResult::Accepted(cell))) => Ok(Some(cell)),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(ReadError::CellDoesNotExisted))) => Ok(None),
            Ok(Ok(TxnExecResult::Error(re))) => Err(TxnError::ReadError(re)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn read_selected(&self, id: Id, fields: Vec<u64>) -> Result<Option<Vec<Value>>, TxnError> {
        match self.client.read_selected(self.tid.to_owned(), id, fields).wait() {
            Ok(Ok(TxnExecResult::Accepted(fields))) => Ok(Some(fields)),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(ReadError::CellDoesNotExisted))) => Ok(None),
            Ok(Ok(TxnExecResult::Error(re))) => Err(TxnError::ReadError(re)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn write(&self, cell: Cell) -> Result<(), TxnError> {
        match self.client.write(self.tid.to_owned(), cell).wait() {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn update(&self, cell: Cell) -> Result<(), TxnError> {
        match self.client.update(self.tid.to_owned(), cell).wait() {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn remove(&self, id: Id) -> Result<(), TxnError> {
        match self.client.remove(self.tid.to_owned(), id).wait() {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn head(&self, id: Id) -> Result<Option<CellHeader>, TxnError> {
        match self.client.head(self.tid.to_owned(), id).wait() {
            Ok(Ok(TxnExecResult::Accepted(head))) => Ok(Some(head)),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(ReadError::CellDoesNotExisted))) => Ok(None),
            Ok(Ok(TxnExecResult::Error(re))) => Err(TxnError::ReadError(re)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn upsert(&self, cell: Cell) -> Result<(), TxnError> {
        match self.head(cell.id()) {
            Ok(Some(_)) => self.update(cell),
            Ok(None) => self.write(cell),
            Err(e) => Err(e),
        }
    }
    pub fn prepare(&self) -> Result<(), TxnError> {
        self.state.set(TxnState::Prepared);
        match self.client.prepare(self.tid.to_owned()).wait() {
            Ok(Ok(TMPrepareResult::Success)) => return Ok(()),
            Ok(Ok(TMPrepareResult::DMPrepareError(DMPrepareResult::NotRealizable))) => {
                Err(TxnError::NotRealizable)
            }
            Ok(Ok(TMPrepareResult::DMCommitError(DMCommitResult::CellChanged(_)))) => {
                Err(TxnError::NotRealizable)
            }
            Ok(Ok(rpr)) => Err(TxnError::PrepareError(rpr)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn commit(&self) -> Result<(), TxnError> {
        self.state.set(TxnState::Committed);
        match self.client.commit(self.tid.to_owned()).wait() {
            Ok(Ok(EndResult::Success)) => return Ok(()),
            Ok(Ok(EndResult::SomeLocksNotReleased)) => return Ok(()),
            Ok(Ok(er)) => Err(TxnError::CommitError(er)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
    pub fn abort(&self) -> Result<(), TxnError> {
        if self.state.get() == TxnState::Aborted {
            return Ok(());
        }
        self.state.set(TxnState::Aborted);
        match self.client.abort(self.tid.to_owned()).wait() {
            Ok(Ok(AbortResult::Success(rollback_failures))) => {
                Err(TxnError::Aborted(rollback_failures))
            }
            Ok(Ok(ar)) => Err(TxnError::AbortError(ar)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e)),
        }
    }
}
<|endoftext|>


<commit_before>
use std::io;
use std::io::{Write};

const ERR_ENCODED_DATA_NOT_UTF8 : &'static str = r#"ERROR: Encoded data isn't printable.

The encoded data couldn't be encoded to valid utf8 and so couldn't be printed to the screen.
Use the "-o" option to write the output directly to a file instead."#;

pub struct StdoutWriter;

impl Write for StdoutWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
        match String::from_utf8(Vec::from(buf)) {
            Ok(encoded) => println!("{}", encoded),
            Err(e) => println!("{}\n\nDetails: {}", ERR_ENCODED_DATA_NOT_UTF8, e)
        }
        Ok(buf.len())
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        Ok(())
    }
}
<commit_msg>Fix issue with extra newline being appended to input read from stdin<commit_after>
use std::io;
use std::io::{Write};

const ERR_ENCODED_DATA_NOT_UTF8 : &'static str = r#"ERROR: Encoded data isn't printable.

The encoded data couldn't be encoded to valid utf8 and so couldn't be printed to the screen.
Use the "-o" option to write the output directly to a file instead."#;

pub struct StdoutWriter;

impl Write for StdoutWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
        match String::from_utf8(Vec::from(buf)) {
            Ok(encoded) => {
                let mut out = io::stdout();
                out.write_all(encoded.as_bytes()).unwrap();
                let _ = out.flush();
            },
            Err(e) => println!("{}\n\nDetails: {}", ERR_ENCODED_DATA_NOT_UTF8, e)
        }
        Ok(buf.len())
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        Ok(())
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate genmesh;
extern crate calx_system;
extern crate calx_window;

use calx_window::{WindowBuilder, Event, Key};

enum Face { East, North, Up, West, South, Down };

impl Face {
    pub fn normal(&self) -> [f32; 3] {
        match self {
            East =>  [1.0,  0.0,  0.0],
            North => [0.0,  1.0,  0.0],
            Up =>    [0.0,  0.0,  1.0],
            West =>  [-1.0, 0.0,  0.0],
            South => [0.0, -1.0,  0.0],
            Down =>  [0.0,  0.0, -1.0],
        }
    }
}

#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 3],
    pub normal: [f32; 3];
    pub color: [f32; 4],
}
implement_vertex!(Vertex, pos, normal, color);

fn main() {
    let mut window = WindowBuilder::new().set_title("Voxel demo").build();

    loop {
        for e in window.events().into_iter() {
            match e {
                Event::Quit => return,
                Event::KeyPress(Key::Escape) => return,
                Event::KeyPress(Key::F12) => {
                    calx_system::save_screenshot("calx", window.screenshot())
                        .unwrap();
                }
                _ => (),
            }
        }
        window.clear(0x7799DDFF);

        // window.display(&mut room);

        window.end_frame();
    }
}
<commit_msg>WIP more voxel stuff<commit_after>#[macro_use]
extern crate glium;
extern crate calx_system;
extern crate calx_window;
extern crate cgmath;

use std::default::Default;
use calx_window::{WindowBuilder, Event, Key};
use cgmath::Angle;

/// Cube face.
#[derive(Copy, Clone)]
enum Face { East, North, Up, West, South, Down }

impl Face {
    /// Normal vector for the face.
    pub fn normal(&self) -> [f32; 3] {
        match *self {
            Face::East =>  [ 1.0,  0.0,  0.0],
            Face::North => [ 0.0,  1.0,  0.0],
            Face::Up =>    [ 0.0,  0.0,  1.0],
            Face::West =>  [-1.0,  0.0,  0.0],
            Face::South => [ 0.0, -1.0,  0.0],
            Face::Down =>  [ 0.0,  0.0, -1.0],
        }
    }

    /// Counter-clockwise vertex list using cube vertex indices.
#[inline]
    pub fn vertices(&self) -> [usize; 4] {
        [[1, 3, 7, 5],
         [2, 6, 7, 3],
         [4, 5, 7, 6],
         [0, 4, 6, 2],
         [0, 1, 5, 4],
         [0, 2, 3, 1]][*self as usize]
    }
}

/// Vertex of a default [0, 0, 0] - [1, 1, 1] cube.
///
/// There are 8 indices, corresponding to 3 bits. The low bit denotes x-axis
/// extension, the middle bit y-axis extension and the high bit z-axis
/// extension.
///
/// ```notrust
///     6 --- 7
///    /:    /|
///   4 --- 5 |
///   | :   | |      Z
///   | 2 ..|.3      | Y
///   |.    |/       |/
///   0 --- 1        o---X
///
/// ```
#[inline]
fn cube_vertex(index: usize) -> [f32; 3] {
    [[0.0, 0.0, 0.0],
     [0.1, 0.0, 0.0],
     [0.0, 0.1, 0.0],
     [0.1, 0.1, 0.0],
     [0.0, 0.0, 0.1],
     [0.1, 0.0, 0.1],
     [0.0, 0.1, 0.1],
     [0.1, 0.1, 0.1]][index]
}

#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 3],
    pub normal: [f32; 3],
    //pub color: [f32; 4],
}
implement_vertex!(Vertex, pos, normal, color);

struct Voxel {
    color: [f32; 4]
}

fn get_voxel(voxelPos: [i32; 3]) -> Option<Voxel> {
    // TODO: Perlin noise landscape or something.
    if voxelPos[2] < 0 {
        Some(Voxel { color: [0.0, 1.0, 0.0, 1.0] })
    } else {
        None
    }
}

fn main() {
    let mut window = WindowBuilder::new().set_title("Voxel demo").build();

    let shader = program!(&window.display,
            150 => {
            vertex: "
                #version 150 core

                uniform mat4 projection;
                uniform mat4 modelview;

                in vec3 position;
                in vec3 normal;
                out vec3 v_position;
                out vec3 v_normal;

                void main() {
                    v_position = position;
                    v_normal = normal;
                    gl_Position = projection * modelview * vec4(v_position, 1.0);
                }
            ",

            fragment: "
                #version 150 core

                in vec3 v_normal;
                out vec4 f_color;
                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * vec3(1.0, 1.0, 1.0);
                    f_color = vec4(color, 1.0);
                }
            ",
            }
        ).unwrap();

    loop {
        for e in window.events().into_iter() {
            match e {
                Event::Quit => return,
                Event::KeyPress(Key::Escape) => return,
                Event::KeyPress(Key::F12) => {
                    calx_system::save_screenshot("calx", window.screenshot())
                        .unwrap();
                }
                _ => (),
            }
        }
        window.clear(0x7799DDFF);

        // Camera setup

        let projection: cgmath::Matrix4<f32> = cgmath::PerspectiveFov {
            fovy: cgmath::Deg::new(90.0).into(),
            aspect: 380.0 / 640.0, // XXX: Hardcoding
            near: 1.0,
            far: 1024.0,
        }.into();

        let modelview: cgmath::Matrix4<f32> = cgmath::Matrix4::look_at(
                cgmath::Point3::new(0.0, -10.0, 10.0),
                cgmath::Point3::new(0.0, 0.0, 0.0),
                cgmath::vec3(0.0, 0.0, 1.0));

        // Convert to the format the shader expects.
        let projection: [[f32; 4]; 4] = projection.into();
        let modelview: [[f32; 4]; 4] = modelview.into();

        let uniforms = uniform! {
            projection: projection,
            modelview: modelview,
        };

        // Draw parameters

        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: glium::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        // Setup the cube model
        let faces = [Face::East, Face::North, Face::Up, Face::West, Face::South, Face::Down];
        let mut vertices = Vec::new();
        let mut indices = Vec::new();
        for f in 0..6 {
            normal = faces[f].normal();
            let idx = vertices.len() as u16;
            for v_idx in faces[f].vertices().iter() {
                vertices.push(
                        Vertex {
                            pos: cube_vertex(v_idx),
                            normal: normal
                        });

            }
            indices.push(idx);
            indices.push(idx + 1);
            indices.push(idx + 2);
            indices.push(idx);
            indices.push(idx + 2);
            indices.push(idx + 3);
        }
        let v_buf = glium::VertexBuffer::new(&window.display, &vertices);
        let i_buf = glium::IndexBuffer::new(&window.display, glium::index::PrimitiveType::TrianglesList, &indices).unwrap();

        // Draw the thing

        let mut target = window.display.draw();
        target.draw(&v_buf, &i_buf, &shader, &uniforms, &params).unwrap();
        target.finish().unwrap();

        // window.display(&mut room);

        window.end_frame();
    }
}
<|endoftext|>


<commit_before>//! Reports metrics to Datadog through their HTTPS API.

use chrono::UTC;
use hyper::client::{Client, RequestBuilder};
use hyper::header::ContentType;
use rustc_serialize::json::{self, Json, ToJson};
use std::collections::BTreeMap;

use super::Forwarder;
use super::super::metrics::AggregatedMetrics;

/// Forwards metrics to Datadog via its HTTPS API.
///
/// See [their documentation][] for more details.
///
/// [their documentation]: http://docs.datadoghq.com/api/
pub struct DatadogForwarder {
    pub api_key: String,
    pub base_url: String,
}

impl DatadogForwarder {
    pub fn new(api_key: &str) -> DatadogForwarder {
        DatadogForwarder {
            api_key: api_key.to_owned(),
            base_url: "https://app.datadoghq.com/api".to_owned(),
        }
    }

    fn serialize_metrics(metrics: AggregatedMetrics) -> Json {
        use super::super::metrics::AggregatedMetricType::*;

        let timestamp = UTC::now().timestamp();

        let series: Vec<Json> = metrics
            .iter()
            .map(|metric| {
                let mut object: BTreeMap<String, Json> = BTreeMap::new();

                let (ref metric_type, ref dim, ref value) = *metric;

                let api_type = match *metric_type {
                    Count   => "count",
                    Measure => "gauge",
                    Sample  => "gauge",
                };

                object.insert("metric".to_owned(), dim.name.to_json());
                object.insert("type".to_owned(), api_type.to_json());
                object.insert("points".to_owned(), Json::Array(vec![
                    Json::Array(vec![ timestamp.to_json(), value.to_json() ]),
                ]));

                object.to_json()
            })
            .collect();

        let mut data: BTreeMap<String, Json> = BTreeMap::new();
        data.insert("series".to_owned(), Json::Array(series));

        // Convert it to a `Json::Object`.
        data.to_json()
    }

    fn post<'a>(&'a self, client: &'a Client, path: &str) -> RequestBuilder {
        let path = format!("{}{}?api_key={}", self.base_url, path, self.api_key);

        client.post(&path)
            .header(ContentType::json())
    }
}

impl Forwarder for DatadogForwarder {
    fn forward_metrics(&self, metrics: AggregatedMetrics) {
        let body = json::encode(&DatadogForwarder::serialize_metrics(metrics)).unwrap();
        let client = Client::new();

        let res = self.post(&client, "/v1/series")
            .body(&body)
            .send();

        match res {
            Err(err) => {
                println!("Datadog HTTP Error: {:#?}", err)
            },
            Ok(res) => {
                if !res.status.is_success() {
                    println!("Datadog API Error: {:#?}", res);
                }
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::DatadogForwarder;
    use super::super::super::metrics::{
        AggregatedMetrics,
        AggregatedMetricType,
        Dimension,
    };

    use rustc_serialize::json::ToJson;

    #[test]
    fn datadog_forwarder_serializes_metrics() {
        let metrics = AggregatedMetrics::with_metrics(vec![
            (AggregatedMetricType::Count, Dimension::with_name("test_count"), 1.0),
        ]);
        let json = DatadogForwarder::serialize_metrics(metrics);

        let series = json.find("series").and_then(|s| s.as_array());
        assert_eq!(series.is_some(), true);

        let series = series.unwrap();
        assert_eq!(series.len(), 1);

        let item = series[0].as_object().unwrap();
        assert_eq!(item.get("metric"), Some(&"test_count".to_json()));
        assert_eq!(item.get("type"),   Some(&"count".to_json()));

        let points = item.get("points").unwrap().as_array().unwrap();
        assert_eq!(points.len(), 1);
        let point = points[0].as_array().unwrap();
        assert_eq!(point.len(), 2);
        let ref value = point[1];
        assert_eq!(value, &1.0.to_json());
    }
}
<commit_msg>Send source to Datadog API<commit_after>//! Reports metrics to Datadog through their HTTPS API.

use chrono::UTC;
use hyper::client::{Client, RequestBuilder};
use hyper::header::ContentType;
use rustc_serialize::json::{self, Json, ToJson};
use std::collections::BTreeMap;

use super::Forwarder;
use super::super::metrics::AggregatedMetrics;

/// Forwards metrics to Datadog via its HTTPS API.
///
/// See [their documentation][] for more details.
///
/// [their documentation]: http://docs.datadoghq.com/api/
pub struct DatadogForwarder {
    pub api_key: String,
    pub base_url: String,
}

impl DatadogForwarder {
    pub fn new(api_key: &str) -> DatadogForwarder {
        DatadogForwarder {
            api_key: api_key.to_owned(),
            base_url: "https://app.datadoghq.com/api".to_owned(),
        }
    }

    fn serialize_metrics(metrics: AggregatedMetrics) -> Json {
        use super::super::metrics::AggregatedMetricType::*;

        let timestamp = UTC::now().timestamp();

        let series: Vec<Json> = metrics
            .iter()
            .map(|metric| {
                let mut object: BTreeMap<String, Json> = BTreeMap::new();

                let (ref metric_type, ref dim, ref value) = *metric;

                let api_type = match *metric_type {
                    Count   => "count",
                    Measure => "gauge",
                    Sample  => "gauge",
                };

                object.insert("metric".to_owned(), dim.name.to_json());
                object.insert("type".to_owned(), api_type.to_json());
                object.insert("points".to_owned(), Json::Array(vec![
                    Json::Array(vec![ timestamp.to_json(), value.to_json() ]),
                ]));

                if let Some(ref source) = dim.source {
                    object.insert("tags".to_owned(), Json::Array(vec![
                        format!("source:{}", source).to_json()
                    ]));
                }

                object.to_json()
            })
            .collect();

        let mut data: BTreeMap<String, Json> = BTreeMap::new();
        data.insert("series".to_owned(), Json::Array(series));

        // Convert it to a `Json::Object`.
        data.to_json()
    }

    fn post<'a>(&'a self, client: &'a Client, path: &str) -> RequestBuilder {
        let path = format!("{}{}?api_key={}", self.base_url, path, self.api_key);

        client.post(&path)
            .header(ContentType::json())
    }
}

impl Forwarder for DatadogForwarder {
    fn forward_metrics(&self, metrics: AggregatedMetrics) {
        let body = json::encode(&DatadogForwarder::serialize_metrics(metrics)).unwrap();
        let client = Client::new();

        let res = self.post(&client, "/v1/series")
            .body(&body)
            .send();

        match res {
            Err(err) => {
                println!("Datadog HTTP Error: {:#?}", err)
            },
            Ok(res) => {
                if !res.status.is_success() {
                    println!("Datadog API Error: {:#?}", res);
                }
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::DatadogForwarder;
    use super::super::super::metrics::{
        AggregatedMetrics,
        AggregatedMetricType,
        Dimension,
    };

    use rustc_serialize::json::ToJson;

    #[test]
    fn datadog_forwarder_serializes_metrics() {
        let metrics = AggregatedMetrics::with_metrics(vec![
            (AggregatedMetricType::Count, Dimension::with_name("test_count"), 1.0),
            (AggregatedMetricType::Count, Dimension::with_name_and_source("test_count", "test_source"), 2.0),
        ]);
        let json = DatadogForwarder::serialize_metrics(metrics);

        let series = json.find("series").and_then(|s| s.as_array());
        assert_eq!(series.is_some(), true);

        let series = series.unwrap();
        assert_eq!(series.len(), 2);

        // First item
        let item = series[0].as_object().unwrap();
        assert_eq!(item.get("metric"), Some(&"test_count".to_json()));
        assert_eq!(item.get("type"), Some(&"count".to_json()));
        assert!(item.get("tags").is_none());

        let points = item.get("points").unwrap().as_array().unwrap();
        assert_eq!(points.len(), 1);
        let point = points[0].as_array().unwrap();
        assert_eq!(point.len(), 2);
        let ref value = point[1];
        assert_eq!(value, &1.0.to_json());

        // Second item
        let item = series[1].as_object().unwrap();
        assert_eq!(item.get("metric"), Some(&"test_count".to_json()));
        assert_eq!(item.get("type"), Some(&"count".to_json()));
        assert!(item.get("tags").is_some());

        let tags = item.get("tags").unwrap().as_array().unwrap();
        assert_eq!(tags.len(), 1);
        let ref tag = tags[0];
        assert_eq!(tag, &"source:test_source".to_json());
    }
}
<|endoftext|>


<commit_before>use tokenizer::TomlFragment;
//use tokenizer::TomlFragment::*;
use super::parser_whitespace::parse_whitespace;
use super::parser_comment::parse_comment;
use super::parser_boolean::parse_boolean;
use super::parser_integer::parse_integer;
use super::parser_array::{parse_bracket_open, parse_bracket_close, parse_comma};
use self::TokenizeResult::{Success, Error};

#[derive(PartialEq, Debug)]
pub enum TokenizeResult<'a> {
    Success(Vec<TomlFragment<'a>>),
    Error(&'a str),
}

pub fn tokenize(s : &str) -> TokenizeResult {
    let mut tokens = Vec::with_capacity(20);

    let mut rest = s;

    while !rest.is_empty() {
        match parse_whitespace(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_comment(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_boolean(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_integer(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_bracket_open(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_bracket_close(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_comma(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        return Error("Tokenize failed");
    }

    Success(tokens)
}

#[test]
fn tokenize_error() {
    assert_eq!(Error("Tokenize failed"), tokenize("!23121312awefa"));
}

#[test]
fn tokenize_empty_str() {
    assert_eq!(Success(vec![]), tokenize(""));
}

#[test]
fn tokenize_whitespace() {
    let tokens = vec![Whitespace(" ")];
    assert_eq!(Success(tokens), tokenize(" "));
}

#[test]
fn tokenize_comment() {
    let tokens = vec![Comment("this is a comment")];
    assert_eq!(Success(tokens), tokenize("#this is a comment"));
}

#[test]
fn tokenize_booleans() {
    let tokens = vec![
        Boolean("true"),
        Whitespace(" "),
        Boolean("false"),
    ];
    assert_eq!(Success(tokens), tokenize("true false"));
}

#[test]
fn tokenize_whitespace_comment() {
    let tokens = vec![
        Whitespace("    \t"),
        Comment("just some whitespace"),
    ];
    assert_eq!(Success(tokens), tokenize("    \t#just some whitespace"));
}

#[test]
fn tokenize_positive_int_whitespace_negative_int() {
    let tokens = vec![
        Integer("123"),
        Whitespace(" "),
        Integer("-456"),
    ];
    assert_eq!(Success(tokens), tokenize("123 -456"));
}

#[test]
fn tokenize_array() {
    let tokens = vec![
        BracketOpen,
        Integer("1"),
        Comma,
        Integer("2"),
        Comma,
        Integer("3"),
        BracketClose,
    ];
    assert_eq!(Success(tokens), tokenize("[1,2,3]"));
}
<commit_msg>Get tests building again<commit_after>use tokenizer::TomlFragment;
use super::parser_whitespace::parse_whitespace;
use super::parser_comment::parse_comment;
use super::parser_boolean::parse_boolean;
use super::parser_integer::parse_integer;
use super::parser_array::{parse_bracket_open, parse_bracket_close, parse_comma};
use self::TokenizeResult::{Success, Error};

#[derive(PartialEq, Debug)]
pub enum TokenizeResult<'a> {
    Success(Vec<TomlFragment<'a>>),
    Error(&'a str),
}

pub fn tokenize(s : &str) -> TokenizeResult {
    let mut tokens = Vec::with_capacity(20);

    let mut rest = s;

    while !rest.is_empty() {
        match parse_whitespace(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_comment(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_boolean(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_integer(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_bracket_open(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_bracket_close(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        match parse_comma(rest) {
            None => {},
            Some(result) => { tokens.push(result.fragment); rest = result.remainder; continue; }
        }

        return Error("Tokenize failed");
    }

    Success(tokens)
}

#[cfg(test)]
mod test {
    use super::tokenize;
    use super::TokenizeResult::{Success, Error};
    use tokenizer::TomlFragment::*;

    #[test]
    fn tokenize_error() {
        assert_eq!(Error("Tokenize failed"), tokenize("!23121312awefa"));
    }

    #[test]
    fn tokenize_empty_str() {
        assert_eq!(Success(vec![]), tokenize(""));
    }

    #[test]
    fn tokenize_whitespace() {
        let tokens = vec![Whitespace(" ")];
        assert_eq!(Success(tokens), tokenize(" "));
    }

    #[test]
    fn tokenize_comment() {
        let tokens = vec![Comment("this is a comment")];
        assert_eq!(Success(tokens), tokenize("#this is a comment"));
    }

    #[test]
    fn tokenize_booleans() {
        let tokens = vec![
            Boolean("true"),
            Whitespace(" "),
            Boolean("false"),
        ];
        assert_eq!(Success(tokens), tokenize("true false"));
    }

    #[test]
    fn tokenize_whitespace_comment() {
        let tokens = vec![
            Whitespace("    \t"),
            Comment("just some whitespace"),
        ];
        assert_eq!(Success(tokens), tokenize("    \t#just some whitespace"));
    }

    #[test]
    fn tokenize_positive_int_whitespace_negative_int() {
        let tokens = vec![
            Integer("123"),
            Whitespace(" "),
            Integer("-456"),
        ];
        assert_eq!(Success(tokens), tokenize("123 -456"));
    }

    #[test]
    fn tokenize_array() {
        let tokens = vec![
            BracketOpen,
            Integer("1"),
            Comma,
            Integer("2"),
            Comma,
            Integer("3"),
            BracketClose,
        ];
        assert_eq!(Success(tokens), tokenize("[1,2,3]"));
    }
}
<|endoftext|>


<commit_before>extern crate cairo;

extern crate gtk;
use gtk::{Inhibit, ToolButtonExt, WidgetExt};

#[cfg(feature = "profiling-audio-draw")]
use chrono::Utc;

use std::boxed::Box;

use std::rc::Rc;
use std::cell::RefCell;

use std::sync::{Arc, Mutex};

use media::{Context, DoubleAudioBuffer, SampleExtractor, Timestamp};

use super::{ControllerState, DoubleWaveformBuffer, MainController, WaveformBuffer,
            WaveformConditions, BACKGROUND_COLOR};

const BUFFER_DURATION: u64 = 60_000_000_000; // 60 s
const MIN_REQ_DURATION: f64 = 1_953_125f64; // 2 ms / 1000 px
const MAX_REQ_DURATION: f64 = 32_000_000_000f64; // 32 s / 1000 px
const INIT_REQ_DURATION: f64 = 4_000_000_000f64; // 4 s / 1000 px
const STEP_REQ_DURATION: f64 = 2f64;

pub struct AudioController {
    container: gtk::Box,
    drawingarea: gtk::DrawingArea,
    zoom_in_btn: gtk::ToolButton,
    zoom_out_btn: gtk::ToolButton,

    is_active: bool,
    playback_needs_refresh: bool,

    requested_duration: f64,

    waveform_mtx: Arc<Mutex<Box<SampleExtractor>>>,
    dbl_buffer_mtx: Arc<Mutex<DoubleAudioBuffer>>,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let dbl_buffer_mtx = DoubleWaveformBuffer::new_mutex(BUFFER_DURATION);
        let waveform_mtx = dbl_buffer_mtx
            .lock()
            .expect("AudioController::new: couldn't lock dbl_buffer_mtx")
            .get_exposed_buffer_mtx();

        Rc::new(RefCell::new(AudioController {
            container: builder.get_object("audio-container").unwrap(),
            drawingarea: builder.get_object("audio-drawingarea").unwrap(),
            zoom_in_btn: builder.get_object("audio_zoom_in-toolbutton").unwrap(),
            zoom_out_btn: builder.get_object("audio_zoom_out-toolbutton").unwrap(),

            is_active: false,
            playback_needs_refresh: false,

            requested_duration: INIT_REQ_DURATION,
            waveform_mtx: waveform_mtx,
            dbl_buffer_mtx: dbl_buffer_mtx,
        }))
    }

    pub fn register_callbacks(
        this_rc: &Rc<RefCell<Self>>,
        main_ctrl: &Rc<RefCell<MainController>>,
    ) {
        let this = this_rc.borrow();

        // draw
        let this_clone = Rc::clone(this_rc);
        this.drawingarea.connect_draw(
            move |drawing_area, cairo_ctx| {
                let mut this = this_clone.borrow_mut();
                this.draw(drawing_area, cairo_ctx)
            },
        );

        // widget size changed
        let main_ctrl_clone = Rc::clone(main_ctrl);
        let this_clone = Rc::clone(this_rc);
        this.drawingarea.connect_size_allocate(move |_, _| {
            this_clone.borrow_mut().refresh(&main_ctrl_clone);
        });

        // click in drawing_area
        let main_ctrl_clone = Rc::clone(main_ctrl);
        let this_clone = Rc::clone(this_rc);
        this.drawingarea.connect_button_press_event(
            move |_, event_button| {
                let button = event_button.get_button();
                if button == 1 {
                    if let Some(position) = {
                        let mut this = this_clone.borrow_mut();
                        let waveform_buffer_grd = &mut *this.waveform_mtx.lock().expect(
                            "Couldn't lock waveform buffer in audio controller draw",
                        );
                        waveform_buffer_grd
                            .as_mut_any()
                            .downcast_mut::<WaveformBuffer>()
                            .expect(concat!(
                                "AudioController::drawingarea::button_press_event ",
                                "SamplesExtratctor is not a waveform buffer",
                            ))
                            .get_position(event_button.get_position().0)
                    }
                    {
                        main_ctrl_clone.borrow_mut().seek(position, true); // accurate (slow)
                    }
                }
                Inhibit(true)
            },
        );

        // click zoom in
        let main_ctrl_clone = Rc::clone(main_ctrl);
        let this_clone = Rc::clone(this_rc);
        this.zoom_in_btn.connect_clicked(move |_| {
            let mut this = this_clone.borrow_mut();
            this.requested_duration /= STEP_REQ_DURATION;
            if this.requested_duration >= MIN_REQ_DURATION {
                this.refresh(&main_ctrl_clone);
            } else {
                this.requested_duration = MIN_REQ_DURATION;
            }
        });

        // click zoom out
        let main_ctrl_clone = Rc::clone(main_ctrl);
        let this_clone = Rc::clone(this_rc);
        this.zoom_out_btn.connect_clicked(move |_| {
            let mut this = this_clone.borrow_mut();
            this.requested_duration *= STEP_REQ_DURATION;
            if this.requested_duration <= MAX_REQ_DURATION {
                this.refresh(&main_ctrl_clone);
            } else {
                this.requested_duration = MAX_REQ_DURATION;
            }
        });
    }

    pub fn cleanup(&mut self) {
        self.is_active = false;
        self.playback_needs_refresh = false;
        {
            self.dbl_buffer_mtx
                .lock()
                .expect("AudioController::cleanup: Couldn't lock dbl_buffer_mtx")
                .cleanup();
        }
        self.requested_duration = INIT_REQ_DURATION;
        self.drawingarea.queue_draw();
    }

    pub fn get_dbl_buffer_mtx(&self) -> Arc<Mutex<DoubleAudioBuffer>> {
        Arc::clone(&self.dbl_buffer_mtx)
    }

    pub fn new_media(&mut self, context: &Context) {
        let has_audio = context
            .info
            .lock()
            .expect(
                "Failed to lock media info while initializing audio controller",
            )
            .audio_best
            .is_some();

        if has_audio {
            self.is_active = true;
            self.container.show();
        } else {
            self.container.hide();
        }
    }

    pub fn seek(&mut self, position: u64, state: &ControllerState) {
        {
            self.waveform_mtx
                .lock()
                .expect("AudioController::seek: Couldn't lock waveform_mtx")
                .as_mut_any()
                .downcast_mut::<WaveformBuffer>()
                .expect(
                    "AudioController::seek: SamplesExtratctor is not a WaveformBuffer",
                )
                .seek(position, *state == ControllerState::Playing);
        }

        if *state == ControllerState::Paused {
            // refresh the buffer in order to render the waveform
            // with samples that might not be rendered in current WaveformImage yet
            self.dbl_buffer_mtx
                .lock()
                .expect("AudioController::seek: couldn't lock dbl_buffer_mtx")
                .refresh(false); // don't keep continuity
        }
        self.drawingarea.queue_draw();
    }

    pub fn tick(&mut self) {
        if self.is_active {
            if self.playback_needs_refresh {
                #[cfg(feature = "trace-audio-controller")]
                println!("AudioController::tick forcing refresh");

                self.dbl_buffer_mtx
                    .lock()
                    .expect("AudioController::tick: couldn't lock dbl_buffer_mtx")
                    .refresh(true); // keep continuity
            }

            self.drawingarea.queue_draw();
        }
    }

    fn clean_cairo_context(&self, cr: &cairo::Context) {
        cr.set_source_rgb(BACKGROUND_COLOR.0, BACKGROUND_COLOR.1, BACKGROUND_COLOR.2);
        cr.paint();
    }

    fn draw(&mut self, drawingarea: &gtk::DrawingArea, cr: &cairo::Context) -> Inhibit {
        #[cfg(feature = "profiling-audio-draw")]
        let before_init = Utc::now();

        let allocation = drawingarea.get_allocation();
        if allocation.width.is_negative() {
            #[cfg(feature = "trace-audio-controller")]
            println!(
                "AudioController::draw negative allocation.width: {}",
                allocation.width
            );

            self.clean_cairo_context(cr);
            return Inhibit(true);
        }

        #[cfg(feature = "profiling-audio-draw")]
        let before_lock = Utc::now();
        #[cfg(feature = "profiling-audio-draw")]
        let mut _before_cndt = Utc::now();
        #[cfg(feature = "profiling-audio-draw")]
        let mut _before_image = Utc::now();

        let image_positions = {
            let waveform_grd = &mut *self.waveform_mtx.lock().expect(
                "AudioController::draw: couldn't lock waveform_mtx",
            );
            let waveform_buffer = waveform_grd
                .as_mut_any()
                .downcast_mut::<WaveformBuffer>()
                .expect(
                    "AudioController::draw: SamplesExtratctor is not a WaveformBuffer",
                );

            #[cfg(feature = "profiling-audio-draw")]
            let _before_cndt = Utc::now();

            waveform_buffer.update_conditions(
                self.requested_duration,
                allocation.width,
                allocation.height,
            );

            self.playback_needs_refresh = waveform_buffer.playback_needs_refresh;

            match waveform_buffer.get_image() {
                Some((image, image_positions)) => {
                    #[cfg(feature = "profiling-audio-draw")]
                    let _before_image = Utc::now();

                    cr.set_source_surface(image, -image_positions.first.x, 0f64);
                    cr.paint();

                    image_positions
                }
                None => {
                    self.clean_cairo_context(cr);

                    #[cfg(feature = "trace-audio-controller")]
                    println!("AudioController::draw no image");

                    return Inhibit(true);
                }
            }
        };

        #[cfg(feature = "profiling-audio-draw")]
        let before_pos = Utc::now();

        let height = f64::from(allocation.height);
        let width = f64::from(allocation.width);
        cr.scale(1f64, 1f64);
        cr.set_source_rgb(1f64, 1f64, 0f64);
        cr.set_font_size(14f64);

        // first position
        let first_text = Timestamp::format(image_positions.first.timestamp, false);
        let first_text_width = 2f64 + cr.text_extents(&first_text).width;
        cr.move_to(2f64, 30f64);
        cr.show_text(&first_text);

        // last position
        if let Some(last_pos) = image_positions.last {
            let last_text = Timestamp::format(last_pos.timestamp, false);
            // align actual width to a 15px multiple box in order to avoid
            // variations due to actual size of individual digits
            let last_text_width = (cr.text_extents(&last_text).width / 15f64).ceil() * 15f64;
            if last_pos.x - last_text_width > first_text_width + 5f64 {
                // last text won't overlap with first text
                cr.move_to(last_pos.x - last_text_width, 30f64);
                cr.show_text(&last_text);
            }
        }

        if let Some(current_pos) = image_positions.current {
            // draw current pos
            let cursor_text = Timestamp::format(current_pos.timestamp, true);
            let cursor_text_width = 5f64 + cr.text_extents(&cursor_text).width;
            let cursor_text_x = if current_pos.x + cursor_text_width < width {
                current_pos.x + 5f64
            } else {
                current_pos.x - cursor_text_width
            };
            cr.move_to(cursor_text_x, 15f64);
            cr.show_text(&cursor_text);

            cr.set_line_width(1f64);
            cr.move_to(current_pos.x, 0f64);
            cr.line_to(current_pos.x, height);
            cr.stroke();
        }

        #[cfg(feature = "profiling-audio-draw")]
        let end = Utc::now();

        #[cfg(feature = "profiling-audio-draw")]
        println!(
            "audio-draw,{},{},{},{},{},{}",
            before_init.time().format("%H:%M:%S%.6f"),
            before_lock.time().format("%H:%M:%S%.6f"),
            _before_cndt.time().format("%H:%M:%S%.6f"),
            _before_image.time().format("%H:%M:%S%.6f"),
            before_pos.time().format("%H:%M:%S%.6f"),
            end.time().format("%H:%M:%S%.6f"),
        );

        Inhibit(true)
    }

    fn refresh(&mut self, main_ctrl: &Rc<RefCell<MainController>>) {
        let allocation = self.drawingarea.get_allocation();
        {
            // refresh the buffer in order to render the waveform
            // in latest conditions
            let requested_duration = self.requested_duration;
            self.dbl_buffer_mtx
                .lock()
                .expect(
                    "AudioController::size-allocate: couldn't lock dbl_buffer_mtx",
                )
                .refresh_with_conditions(
                    Box::new(WaveformConditions::new(
                        requested_duration,
                        allocation.width,
                        allocation.height,
                    )),
                    *main_ctrl.borrow().get_state() == ControllerState::Playing,
                );
        }

        self.drawingarea.queue_draw();
    }
}
<commit_msg>AudioController: make sure background is completely filled (#72)<commit_after>extern crate cairo;

extern crate gtk;
use gtk::{Inhibit, ToolButtonExt, WidgetExt};

#[cfg(feature = "profiling-audio-draw")]
use chrono::Utc;

use std::boxed::Box;

use std::rc::Rc;
use std::cell::RefCell;

use std::sync::{Arc, Mutex};

use media::{Context, DoubleAudioBuffer, SampleExtractor, Timestamp};

use super::{ControllerState, DoubleWaveformBuffer, MainController, WaveformBuffer,
            WaveformConditions, BACKGROUND_COLOR};

const BUFFER_DURATION: u64 = 60_000_000_000; // 60 s
const MIN_REQ_DURATION: f64 = 1_953_125f64; // 2 ms / 1000 px
const MAX_REQ_DURATION: f64 = 32_000_000_000f64; // 32 s / 1000 px
const INIT_REQ_DURATION: f64 = 4_000_000_000f64; // 4 s / 1000 px
const STEP_REQ_DURATION: f64 = 2f64;

pub struct AudioController {
    container: gtk::Box,
    drawingarea: gtk::DrawingArea,
    zoom_in_btn: gtk::ToolButton,
    zoom_out_btn: gtk::ToolButton,

    is_active: bool,
    playback_needs_refresh: bool,

    requested_duration: f64,

    waveform_mtx: Arc<Mutex<Box<SampleExtractor>>>,
    dbl_buffer_mtx: Arc<Mutex<DoubleAudioBuffer>>,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let dbl_buffer_mtx = DoubleWaveformBuffer::new_mutex(BUFFER_DURATION);
        let waveform_mtx = dbl_buffer_mtx
            .lock()
            .expect("AudioController::new: couldn't lock dbl_buffer_mtx")
            .get_exposed_buffer_mtx();

        Rc::new(RefCell::new(AudioController {
            container: builder.get_object("audio-container").unwrap(),
            drawingarea: builder.get_object("audio-drawingarea").unwrap(),
            zoom_in_btn: builder.get_object("audio_zoom_in-toolbutton").unwrap(),
            zoom_out_btn: builder.get_object("audio_zoom_out-toolbutton").unwrap(),

            is_active: false,
            playback_needs_refresh: false,

            requested_duration: INIT_REQ_DURATION,
            waveform_mtx: waveform_mtx,
            dbl_buffer_mtx: dbl_buffer_mtx,
        }))
    }

    pub fn register_callbacks(
        this_rc: &Rc<RefCell<Self>>,
        main_ctrl: &Rc<RefCell<MainController>>,
    ) {
        let this = this_rc.borrow();

        // draw
        let this_clone = Rc::clone(this_rc);
        this.drawingarea.connect_draw(
            move |drawing_area, cairo_ctx| {
                let mut this = this_clone.borrow_mut();
                this.draw(drawing_area, cairo_ctx)
            },
        );

        // widget size changed
        let main_ctrl_clone = Rc::clone(main_ctrl);
        let this_clone = Rc::clone(this_rc);
        this.drawingarea.connect_size_allocate(move |_, _| {
            this_clone.borrow_mut().refresh(&main_ctrl_clone);
        });

        // click in drawing_area
        let main_ctrl_clone = Rc::clone(main_ctrl);
        let this_clone = Rc::clone(this_rc);
        this.drawingarea.connect_button_press_event(
            move |_, event_button| {
                let button = event_button.get_button();
                if button == 1 {
                    if let Some(position) = {
                        let mut this = this_clone.borrow_mut();
                        let waveform_buffer_grd = &mut *this.waveform_mtx.lock().expect(
                            "Couldn't lock waveform buffer in audio controller draw",
                        );
                        waveform_buffer_grd
                            .as_mut_any()
                            .downcast_mut::<WaveformBuffer>()
                            .expect(concat!(
                                "AudioController::drawingarea::button_press_event ",
                                "SamplesExtratctor is not a waveform buffer",
                            ))
                            .get_position(event_button.get_position().0)
                    }
                    {
                        main_ctrl_clone.borrow_mut().seek(position, true); // accurate (slow)
                    }
                }
                Inhibit(true)
            },
        );

        // click zoom in
        let main_ctrl_clone = Rc::clone(main_ctrl);
        let this_clone = Rc::clone(this_rc);
        this.zoom_in_btn.connect_clicked(move |_| {
            let mut this = this_clone.borrow_mut();
            this.requested_duration /= STEP_REQ_DURATION;
            if this.requested_duration >= MIN_REQ_DURATION {
                this.refresh(&main_ctrl_clone);
            } else {
                this.requested_duration = MIN_REQ_DURATION;
            }
        });

        // click zoom out
        let main_ctrl_clone = Rc::clone(main_ctrl);
        let this_clone = Rc::clone(this_rc);
        this.zoom_out_btn.connect_clicked(move |_| {
            let mut this = this_clone.borrow_mut();
            this.requested_duration *= STEP_REQ_DURATION;
            if this.requested_duration <= MAX_REQ_DURATION {
                this.refresh(&main_ctrl_clone);
            } else {
                this.requested_duration = MAX_REQ_DURATION;
            }
        });
    }

    pub fn cleanup(&mut self) {
        self.is_active = false;
        self.playback_needs_refresh = false;
        {
            self.dbl_buffer_mtx
                .lock()
                .expect("AudioController::cleanup: Couldn't lock dbl_buffer_mtx")
                .cleanup();
        }
        self.requested_duration = INIT_REQ_DURATION;
        self.drawingarea.queue_draw();
    }

    pub fn get_dbl_buffer_mtx(&self) -> Arc<Mutex<DoubleAudioBuffer>> {
        Arc::clone(&self.dbl_buffer_mtx)
    }

    pub fn new_media(&mut self, context: &Context) {
        let has_audio = context
            .info
            .lock()
            .expect(
                "Failed to lock media info while initializing audio controller",
            )
            .audio_best
            .is_some();

        if has_audio {
            self.is_active = true;
            self.container.show();
        } else {
            self.container.hide();
        }
    }

    pub fn seek(&mut self, position: u64, state: &ControllerState) {
        {
            self.waveform_mtx
                .lock()
                .expect("AudioController::seek: Couldn't lock waveform_mtx")
                .as_mut_any()
                .downcast_mut::<WaveformBuffer>()
                .expect(
                    "AudioController::seek: SamplesExtratctor is not a WaveformBuffer",
                )
                .seek(position, *state == ControllerState::Playing);
        }

        if *state == ControllerState::Paused {
            // refresh the buffer in order to render the waveform
            // with samples that might not be rendered in current WaveformImage yet
            self.dbl_buffer_mtx
                .lock()
                .expect("AudioController::seek: couldn't lock dbl_buffer_mtx")
                .refresh(false); // don't keep continuity
        }
        self.drawingarea.queue_draw();
    }

    pub fn tick(&mut self) {
        if self.is_active {
            if self.playback_needs_refresh {
                #[cfg(feature = "trace-audio-controller")]
                println!("AudioController::tick forcing refresh");

                self.dbl_buffer_mtx
                    .lock()
                    .expect("AudioController::tick: couldn't lock dbl_buffer_mtx")
                    .refresh(true); // keep continuity
            }

            self.drawingarea.queue_draw();
        }
    }

    fn clean_cairo_context(&self, cr: &cairo::Context) {
        cr.set_source_rgb(BACKGROUND_COLOR.0, BACKGROUND_COLOR.1, BACKGROUND_COLOR.2);
        cr.paint();
    }

    fn draw(&mut self, drawingarea: &gtk::DrawingArea, cr: &cairo::Context) -> Inhibit {
        #[cfg(feature = "profiling-audio-draw")]
        let before_init = Utc::now();

        let allocation = drawingarea.get_allocation();
        if allocation.width.is_negative() {
            #[cfg(feature = "trace-audio-controller")]
            println!(
                "AudioController::draw negative allocation.width: {}",
                allocation.width
            );

            self.clean_cairo_context(cr);
            return Inhibit(true);
        }

        #[cfg(feature = "profiling-audio-draw")]
        let before_lock = Utc::now();
        #[cfg(feature = "profiling-audio-draw")]
        let mut _before_cndt = Utc::now();
        #[cfg(feature = "profiling-audio-draw")]
        let mut _before_image = Utc::now();

        let image_positions = {
            let waveform_grd = &mut *self.waveform_mtx.lock().expect(
                "AudioController::draw: couldn't lock waveform_mtx",
            );
            let waveform_buffer = waveform_grd
                .as_mut_any()
                .downcast_mut::<WaveformBuffer>()
                .expect(
                    "AudioController::draw: SamplesExtratctor is not a WaveformBuffer",
                );

            #[cfg(feature = "profiling-audio-draw")]
            let _before_cndt = Utc::now();

            waveform_buffer.update_conditions(
                self.requested_duration,
                allocation.width,
                allocation.height,
            );

            self.playback_needs_refresh = waveform_buffer.playback_needs_refresh;

            match waveform_buffer.get_image() {
                Some((image, image_positions)) => {
                    #[cfg(feature = "profiling-audio-draw")]
                    let _before_image = Utc::now();

                    cr.set_source_surface(image, -image_positions.first.x, 0f64);
                    cr.paint();

                    image_positions
                }
                None => {
                    self.clean_cairo_context(cr);

                    #[cfg(feature = "trace-audio-controller")]
                    println!("AudioController::draw no image");

                    return Inhibit(true);
                }
            }
        };

        #[cfg(feature = "profiling-audio-draw")]
        let before_pos = Utc::now();

        let height = f64::from(allocation.height);
        let width = f64::from(allocation.width);
        cr.scale(1f64, 1f64);
        cr.set_source_rgb(1f64, 1f64, 0f64);
        cr.set_font_size(14f64);

        // first position
        let first_text = Timestamp::format(image_positions.first.timestamp, false);
        let first_text_width = 2f64 + cr.text_extents(&first_text).width;
        cr.move_to(2f64, 30f64);
        cr.show_text(&first_text);

        // last position
        if let Some(last_pos) = image_positions.last {
            let last_text = Timestamp::format(last_pos.timestamp, false);
            // align actual width to a 15px multiple box in order to avoid
            // variations due to actual size of individual digits
            let last_text_width = (cr.text_extents(&last_text).width / 15f64).ceil() * 15f64;
            if last_pos.x - last_text_width > first_text_width + 5f64 {
                // last text won't overlap with first text
                cr.move_to(last_pos.x - last_text_width, 30f64);
                cr.show_text(&last_text);
            }

            // make sure the rest of the image is filled with background's color
            cr.set_source_rgb(BACKGROUND_COLOR.0, BACKGROUND_COLOR.1, BACKGROUND_COLOR.2);
            cr.rectangle(last_pos.x, 0f64, width - last_pos.x, height);
            cr.fill();
        }

        if let Some(current_pos) = image_positions.current {
            // draw current pos
            cr.set_source_rgb(1f64, 1f64, 0f64);

            let cursor_text = Timestamp::format(current_pos.timestamp, true);
            let cursor_text_width = 5f64 + cr.text_extents(&cursor_text).width;
            let cursor_text_x = if current_pos.x + cursor_text_width < width {
                current_pos.x + 5f64
            } else {
                current_pos.x - cursor_text_width
            };
            cr.move_to(cursor_text_x, 15f64);
            cr.show_text(&cursor_text);

            cr.set_line_width(1f64);
            cr.move_to(current_pos.x, 0f64);
            cr.line_to(current_pos.x, height);
            cr.stroke();
        }

        #[cfg(feature = "profiling-audio-draw")]
        let end = Utc::now();

        #[cfg(feature = "profiling-audio-draw")]
        println!(
            "audio-draw,{},{},{},{},{},{}",
            before_init.time().format("%H:%M:%S%.6f"),
            before_lock.time().format("%H:%M:%S%.6f"),
            _before_cndt.time().format("%H:%M:%S%.6f"),
            _before_image.time().format("%H:%M:%S%.6f"),
            before_pos.time().format("%H:%M:%S%.6f"),
            end.time().format("%H:%M:%S%.6f"),
        );

        Inhibit(true)
    }

    fn refresh(&mut self, main_ctrl: &Rc<RefCell<MainController>>) {
        let allocation = self.drawingarea.get_allocation();
        {
            // refresh the buffer in order to render the waveform
            // in latest conditions
            let requested_duration = self.requested_duration;
            self.dbl_buffer_mtx
                .lock()
                .expect(
                    "AudioController::size-allocate: couldn't lock dbl_buffer_mtx",
                )
                .refresh_with_conditions(
                    Box::new(WaveformConditions::new(
                        requested_duration,
                        allocation.width,
                        allocation.height,
                    )),
                    *main_ctrl.borrow().get_state() == ControllerState::Playing,
                );
        }

        self.drawingarea.queue_draw();
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate arg_parser;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use arg_parser::ArgParser;
use extra::io::WriteExt;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{yes} */ r#"
NAME
    yes - print the letter y or a given word, forever.

SYNOPSIS
    yes [ [ -h | --help ] | [ word ] ]

DESCRIPTION
    The yes utility prints the word passed as an operand, forever. If no operand is passed, then
    it defaults to the letter 'y'.

OPTIONS
    -h
    --help
        Print this manual page.
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }

    if parser.args.is_empty() {
        loop {
            stdout.writeln(b"y").try(&mut stderr);
        }
    }
    else {
        let answer = parser.args.join(" ");
        let print = answer.as_bytes();
        loop {
            stdout.writeln(print).try(&mut stderr);
        }
    }
}
<commit_msg>'yes' shows invalid parameter error rather than silence 'y'<commit_after>#![deny(warnings)]

extern crate arg_parser;
extern crate extra;

use std::env;
use std::process;
use std::io::{stdout, stderr, Write};
use arg_parser::ArgParser;
use extra::io::WriteExt;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{yes} */ r#"
NAME
    yes - print the letter y or a given word, forever.

SYNOPSIS
    yes [ [ -h | --help ] | [ word ] ]

DESCRIPTION
    The yes utility prints the word passed as an operand, forever. If no operand is passed, then
    it defaults to the letter 'y'.

OPTIONS
    -h
    --help
        Print this manual page.
"#; /* @MANEND */

const HELP_INFO:       &'static str = "Try ‘yes --help’ for more information.\n";

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }

    if let Err(err) = parser.found_invalid() {
        stderr.write_all(err.as_bytes()).try(&mut stderr);
        stdout.write_all(HELP_INFO.as_bytes()).try(&mut stderr);
        stderr.flush().try(&mut stderr);
        process::exit(1);
    }

    let answer = if parser.args.is_empty() {
        "y".to_owned()
    } else {
        parser.args.join(" ")
    };
    let print = answer.as_bytes();
    loop {
        stdout.writeln(print).try(&mut stderr);
    }
}
<|endoftext|>


<commit_before>pub fn toggle_bit(num: u32, bit_index: usize) -> u32 {
    num ^ (1 << bit_index)
}
<commit_msg>bit_ops more comprehensive, with tests<commit_after>/// `start` and `end` are 0-based from LSB (least significant bit).
/// `start` is inclusive and `end` is exclusive.
pub fn get_bits(bits: u32, start: usize, end: usize) -> u32 {
    // !0 is equal to 0xffffffff
    let mask = !(!0 << (end - start + 1));
    (bits >> start) & mask
}

pub fn set_bit(bits: u32, bit_index: usize) -> u32 {
    let mask = 1 << bit_index;
    bits | mask
}

pub fn clear_bit(bits: u32, bit_index: usize) -> u32 {
    let mask = !(1 << bit_index);
    bits & mask
}

pub fn toggle_bit(bits: u32, bit_index: usize) -> u32 {
    let mask = 1 << bit_index;
    bits ^ mask
}

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

    #[test]
    fn test_get_bits() {
        assert_eq!(0xff, get_bits(0xff000000, 24, 32));
    }

    #[test]
    fn test_set_bit() {
        assert_eq!(0b1011, set_bit(0b1010, 0));
        assert_eq!(0b1011, set_bit(0b1011, 0));
        assert_eq!(0b1010, set_bit(0b0010, 3));
    }

    #[test]
    fn test_clear_bit() {
        assert_eq!(0b1010, clear_bit(0b1011, 0));
        assert_eq!(0b1010, clear_bit(0b1010, 0));
        assert_eq!(0b0010, clear_bit(0b1010, 3));
    }

    #[test]
    fn test_toggle_bit() {
        assert_eq!(0b1011, toggle_bit(0b1010, 0));
        assert_eq!(0b1010, toggle_bit(0b1011, 0));
        assert_eq!(0b1010, toggle_bit(0b0010, 3));
    }
}
<|endoftext|>