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

//! A wrapper over an element and a snapshot, that allows us to selector-match
//! against a past state of the element.

use {Atom, CaseSensitivityExt, LocalName, Namespace};
use dom::TElement;
use element_state::ElementState;
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
use selectors::{Element, OpaqueElement};
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::matching::RelevantLinkStatus;
use std::cell::Cell;
use std::fmt;

/// In order to compute restyle hints, we perform a selector match against a
/// list of partial selectors whose rightmost simple selector may be sensitive
/// to the thing being changed. We do this matching twice, once for the element
/// as it exists now and once for the element as it existed at the time of the
/// last restyle. If the results of the selector match differ, that means that
/// the given partial selector is sensitive to the change, and we compute a
/// restyle hint based on its combinator.
///
/// In order to run selector matching against the old element state, we generate
/// a wrapper for the element which claims to have the old state. This is the
/// ElementWrapper logic below.
///
/// Gecko does this differently for element states, and passes a mask called
/// mStateMask, which indicates the states that need to be ignored during
/// selector matching. This saves an ElementWrapper allocation and an additional
/// selector match call at the expense of additional complexity inside the
/// selector matching logic. This only works for boolean states though, so we
/// still need to take the ElementWrapper approach for attribute-dependent
/// style. So we do it the same both ways for now to reduce complexity, but it's
/// worth measuring the performance impact (if any) of the mStateMask approach.
pub trait ElementSnapshot : Sized {
    /// The state of the snapshot, if any.
    fn state(&self) -> Option<ElementState>;

    /// If this snapshot contains attribute information.
    fn has_attrs(&self) -> bool;

    /// The ID attribute per this snapshot. Should only be called if
    /// `has_attrs()` returns true.
    fn id_attr(&self) -> Option<Atom>;

    /// Whether this snapshot contains the class `name`. Should only be called
    /// if `has_attrs()` returns true.
    fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool;

    /// A callback that should be called for each class of the snapshot. Should
    /// only be called if `has_attrs()` returns true.
    fn each_class<F>(&self, F)
        where F: FnMut(&Atom);

    /// The `xml:lang=""` or `lang=""` attribute value per this snapshot.
    fn lang_attr(&self) -> Option<AttrValue>;
}

/// A simple wrapper over an element and a snapshot, that allows us to
/// selector-match against a past state of the element.
#[derive(Clone)]
pub struct ElementWrapper<'a, E>
    where E: TElement,
{
    element: E,
    cached_snapshot: Cell<Option<&'a Snapshot>>,
    snapshot_map: &'a SnapshotMap,
}

impl<'a, E> ElementWrapper<'a, E>
    where E: TElement,
{
    /// Trivially constructs an `ElementWrapper`.
    pub fn new(el: E, snapshot_map: &'a SnapshotMap) -> Self {
        ElementWrapper {
            element: el,
            cached_snapshot: Cell::new(None),
            snapshot_map: snapshot_map,
        }
    }

    /// Gets the snapshot associated with this element, if any.
    pub fn snapshot(&self) -> Option<&'a Snapshot> {
        if !self.element.has_snapshot() {
            return None;
        }

        if let Some(s) = self.cached_snapshot.get() {
            return Some(s);
        }

        let snapshot = self.snapshot_map.get(&self.element);
        debug_assert!(snapshot.is_some(), "has_snapshot lied!");

        self.cached_snapshot.set(snapshot);

        snapshot
    }

    /// Returns the states that have changed since the element was snapshotted.
    pub fn state_changes(&self) -> ElementState {
        let snapshot = match self.snapshot() {
            Some(s) => s,
            None => return ElementState::empty(),
        };

        match snapshot.state() {
            Some(state) => state ^ self.element.get_state(),
            None => ElementState::empty(),
        }
    }

    /// Returns the value of the `xml:lang=""` (or, if appropriate, `lang=""`)
    /// attribute from this element's snapshot or the closest ancestor
    /// element snapshot with the attribute specified.
    fn get_lang(&self) -> Option<AttrValue> {
        let mut current = self.clone();
        loop {
            let lang = match self.snapshot() {
                Some(snapshot) if snapshot.has_attrs() => snapshot.lang_attr(),
                _ => current.element.lang_attr(),
            };
            if lang.is_some() {
                return lang;
            }
            match current.parent_element() {
                Some(parent) => current = parent,
                None => return None,
            }
        }
    }
}

impl<'a, E> fmt::Debug for ElementWrapper<'a, E>
    where E: TElement,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Ignore other fields for now, can change later if needed.
        self.element.fmt(f)
    }
}

impl<'a, E> Element for ElementWrapper<'a, E>
    where E: TElement,
{
    type Impl = SelectorImpl;

    fn match_non_ts_pseudo_class<F>(
        &self,
        pseudo_class: &NonTSPseudoClass,
        context: &mut MatchingContext<Self::Impl>,
        relevant_link: &RelevantLinkStatus,
        _setter: &mut F,
    ) -> bool
    where
         F: FnMut(&Self, ElementSelectorFlags),
    {
        // Some pseudo-classes need special handling to evaluate them against
        // the snapshot.
        match *pseudo_class {
            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozAny(ref selectors) => {
                use selectors::matching::matches_complex_selector;
                context.nesting_level += 1;
                let result = selectors.iter().any(|s| {
                    matches_complex_selector(s.iter(), self, context, _setter)
                });
                context.nesting_level -= 1;
                return result
            }

            // :dir is implemented in terms of state flags, but which state flag
            // it maps to depends on the argument to :dir.  That means we can't
            // just add its state flags to the NonTSPseudoClass, because if we
            // added all of them there, and tested via intersects() here, we'd
            // get incorrect behavior for :not(:dir()) cases.
            //
            // FIXME(bz): How can I set this up so once Servo adds :dir()
            // support we don't forget to update this code?
            #[cfg(feature = "gecko")]
            NonTSPseudoClass::Dir(ref s) => {
                use invalidation::element::invalidation_map::dir_selector_to_state;
                let selector_flag = dir_selector_to_state(s);
                if selector_flag.is_empty() {
                    // :dir() with some random argument; does not match.
                    return false;
                }
                let state = match self.snapshot().and_then(|s| s.state()) {
                    Some(snapshot_state) => snapshot_state,
                    None => self.element.get_state(),
                };
                return state.contains(selector_flag);
            }

            // For :link and :visited, we don't actually want to test the element
            // state directly.  Instead, we use the `relevant_link` to determine if
            // they match.
            NonTSPseudoClass::Link => {
                return relevant_link.is_unvisited(self, context);
            }
            NonTSPseudoClass::Visited => {
                return relevant_link.is_visited(self, context);
            }

            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozTableBorderNonzero => {
                if let Some(snapshot) = self.snapshot() {
                    if snapshot.has_other_pseudo_class_state() {
                        return snapshot.mIsTableBorderNonzero();
                    }
                }
            }

            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozBrowserFrame => {
                if let Some(snapshot) = self.snapshot() {
                    if snapshot.has_other_pseudo_class_state() {
                        return snapshot.mIsMozBrowserFrame();
                    }
                }
            }

            // :lang() needs to match using the closest ancestor xml:lang="" or
            // lang="" attribtue from snapshots.
            NonTSPseudoClass::Lang(ref lang_arg) => {
                return self.element.match_element_lang(Some(self.get_lang()), lang_arg);
            }

            _ => {}
        }

        let flag = pseudo_class.state_flag();
        if flag.is_empty() {
            return self.element.match_non_ts_pseudo_class(
                pseudo_class,
                context,
                relevant_link,
                &mut |_, _| {},
            )
        }
        match self.snapshot().and_then(|s| s.state()) {
            Some(snapshot_state) => snapshot_state.intersects(flag),
            None => {
                self.element.match_non_ts_pseudo_class(
                    pseudo_class,
                    context,
                    relevant_link,
                    &mut |_, _| {},
                )
            }
        }
    }

    fn match_pseudo_element(
        &self,
        pseudo_element: &PseudoElement,
        context: &mut MatchingContext<Self::Impl>,
    ) -> bool {
        self.element.match_pseudo_element(pseudo_element, context)
    }

    fn is_link(&self) -> bool {
        self.element.is_link()
    }

    fn opaque(&self) -> OpaqueElement {
        self.element.opaque()
    }

    fn parent_element(&self) -> Option<Self> {
        self.element.parent_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn first_child_element(&self) -> Option<Self> {
        self.element.first_child_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn last_child_element(&self) -> Option<Self> {
        self.element.last_child_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn prev_sibling_element(&self) -> Option<Self> {
        self.element.prev_sibling_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn next_sibling_element(&self) -> Option<Self> {
        self.element.next_sibling_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn is_html_element_in_html_document(&self) -> bool {
        self.element.is_html_element_in_html_document()
    }

    fn get_local_name(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName {
        self.element.get_local_name()
    }

    fn get_namespace(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl {
        self.element.get_namespace()
    }

    fn attr_matches(&self,
                    ns: &NamespaceConstraint<&Namespace>,
                    local_name: &LocalName,
                    operation: &AttrSelectorOperation<&AttrValue>)
                    -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.attr_matches(ns, local_name, operation)
            }
            _ => self.element.attr_matches(ns, local_name, operation)
        }
    }

    fn has_id(&self, id: &Atom, case_sensitivity: CaseSensitivity) -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.id_attr().map_or(false, |atom| case_sensitivity.eq_atom(&atom, id))
            }
            _ => self.element.has_id(id, case_sensitivity)
        }
    }

    fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.has_class(name, case_sensitivity)
            }
            _ => self.element.has_class(name, case_sensitivity)
        }
    }

    fn is_empty(&self) -> bool {
        self.element.is_empty()
    }

    fn is_root(&self) -> bool {
        self.element.is_root()
    }

    fn pseudo_element_originating_element(&self) -> Option<Self> {
        self.element.pseudo_element_originating_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }
}
<commit_msg>style: Properly forward ElementWrapper::blocks_ancestor_combinators.<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/. */

//! A wrapper over an element and a snapshot, that allows us to selector-match
//! against a past state of the element.

use {Atom, CaseSensitivityExt, LocalName, Namespace};
use dom::TElement;
use element_state::ElementState;
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
use selectors::{Element, OpaqueElement};
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::matching::RelevantLinkStatus;
use std::cell::Cell;
use std::fmt;

/// In order to compute restyle hints, we perform a selector match against a
/// list of partial selectors whose rightmost simple selector may be sensitive
/// to the thing being changed. We do this matching twice, once for the element
/// as it exists now and once for the element as it existed at the time of the
/// last restyle. If the results of the selector match differ, that means that
/// the given partial selector is sensitive to the change, and we compute a
/// restyle hint based on its combinator.
///
/// In order to run selector matching against the old element state, we generate
/// a wrapper for the element which claims to have the old state. This is the
/// ElementWrapper logic below.
///
/// Gecko does this differently for element states, and passes a mask called
/// mStateMask, which indicates the states that need to be ignored during
/// selector matching. This saves an ElementWrapper allocation and an additional
/// selector match call at the expense of additional complexity inside the
/// selector matching logic. This only works for boolean states though, so we
/// still need to take the ElementWrapper approach for attribute-dependent
/// style. So we do it the same both ways for now to reduce complexity, but it's
/// worth measuring the performance impact (if any) of the mStateMask approach.
pub trait ElementSnapshot : Sized {
    /// The state of the snapshot, if any.
    fn state(&self) -> Option<ElementState>;

    /// If this snapshot contains attribute information.
    fn has_attrs(&self) -> bool;

    /// The ID attribute per this snapshot. Should only be called if
    /// `has_attrs()` returns true.
    fn id_attr(&self) -> Option<Atom>;

    /// Whether this snapshot contains the class `name`. Should only be called
    /// if `has_attrs()` returns true.
    fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool;

    /// A callback that should be called for each class of the snapshot. Should
    /// only be called if `has_attrs()` returns true.
    fn each_class<F>(&self, F)
        where F: FnMut(&Atom);

    /// The `xml:lang=""` or `lang=""` attribute value per this snapshot.
    fn lang_attr(&self) -> Option<AttrValue>;
}

/// A simple wrapper over an element and a snapshot, that allows us to
/// selector-match against a past state of the element.
#[derive(Clone)]
pub struct ElementWrapper<'a, E>
    where E: TElement,
{
    element: E,
    cached_snapshot: Cell<Option<&'a Snapshot>>,
    snapshot_map: &'a SnapshotMap,
}

impl<'a, E> ElementWrapper<'a, E>
    where E: TElement,
{
    /// Trivially constructs an `ElementWrapper`.
    pub fn new(el: E, snapshot_map: &'a SnapshotMap) -> Self {
        ElementWrapper {
            element: el,
            cached_snapshot: Cell::new(None),
            snapshot_map: snapshot_map,
        }
    }

    /// Gets the snapshot associated with this element, if any.
    pub fn snapshot(&self) -> Option<&'a Snapshot> {
        if !self.element.has_snapshot() {
            return None;
        }

        if let Some(s) = self.cached_snapshot.get() {
            return Some(s);
        }

        let snapshot = self.snapshot_map.get(&self.element);
        debug_assert!(snapshot.is_some(), "has_snapshot lied!");

        self.cached_snapshot.set(snapshot);

        snapshot
    }

    /// Returns the states that have changed since the element was snapshotted.
    pub fn state_changes(&self) -> ElementState {
        let snapshot = match self.snapshot() {
            Some(s) => s,
            None => return ElementState::empty(),
        };

        match snapshot.state() {
            Some(state) => state ^ self.element.get_state(),
            None => ElementState::empty(),
        }
    }

    /// Returns the value of the `xml:lang=""` (or, if appropriate, `lang=""`)
    /// attribute from this element's snapshot or the closest ancestor
    /// element snapshot with the attribute specified.
    fn get_lang(&self) -> Option<AttrValue> {
        let mut current = self.clone();
        loop {
            let lang = match self.snapshot() {
                Some(snapshot) if snapshot.has_attrs() => snapshot.lang_attr(),
                _ => current.element.lang_attr(),
            };
            if lang.is_some() {
                return lang;
            }
            match current.parent_element() {
                Some(parent) => current = parent,
                None => return None,
            }
        }
    }
}

impl<'a, E> fmt::Debug for ElementWrapper<'a, E>
    where E: TElement,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Ignore other fields for now, can change later if needed.
        self.element.fmt(f)
    }
}

impl<'a, E> Element for ElementWrapper<'a, E>
    where E: TElement,
{
    type Impl = SelectorImpl;

    fn match_non_ts_pseudo_class<F>(
        &self,
        pseudo_class: &NonTSPseudoClass,
        context: &mut MatchingContext<Self::Impl>,
        relevant_link: &RelevantLinkStatus,
        _setter: &mut F,
    ) -> bool
    where
         F: FnMut(&Self, ElementSelectorFlags),
    {
        // Some pseudo-classes need special handling to evaluate them against
        // the snapshot.
        match *pseudo_class {
            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozAny(ref selectors) => {
                use selectors::matching::matches_complex_selector;
                context.nesting_level += 1;
                let result = selectors.iter().any(|s| {
                    matches_complex_selector(s.iter(), self, context, _setter)
                });
                context.nesting_level -= 1;
                return result
            }

            // :dir is implemented in terms of state flags, but which state flag
            // it maps to depends on the argument to :dir.  That means we can't
            // just add its state flags to the NonTSPseudoClass, because if we
            // added all of them there, and tested via intersects() here, we'd
            // get incorrect behavior for :not(:dir()) cases.
            //
            // FIXME(bz): How can I set this up so once Servo adds :dir()
            // support we don't forget to update this code?
            #[cfg(feature = "gecko")]
            NonTSPseudoClass::Dir(ref s) => {
                use invalidation::element::invalidation_map::dir_selector_to_state;
                let selector_flag = dir_selector_to_state(s);
                if selector_flag.is_empty() {
                    // :dir() with some random argument; does not match.
                    return false;
                }
                let state = match self.snapshot().and_then(|s| s.state()) {
                    Some(snapshot_state) => snapshot_state,
                    None => self.element.get_state(),
                };
                return state.contains(selector_flag);
            }

            // For :link and :visited, we don't actually want to test the element
            // state directly.  Instead, we use the `relevant_link` to determine if
            // they match.
            NonTSPseudoClass::Link => {
                return relevant_link.is_unvisited(self, context);
            }
            NonTSPseudoClass::Visited => {
                return relevant_link.is_visited(self, context);
            }

            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozTableBorderNonzero => {
                if let Some(snapshot) = self.snapshot() {
                    if snapshot.has_other_pseudo_class_state() {
                        return snapshot.mIsTableBorderNonzero();
                    }
                }
            }

            #[cfg(feature = "gecko")]
            NonTSPseudoClass::MozBrowserFrame => {
                if let Some(snapshot) = self.snapshot() {
                    if snapshot.has_other_pseudo_class_state() {
                        return snapshot.mIsMozBrowserFrame();
                    }
                }
            }

            // :lang() needs to match using the closest ancestor xml:lang="" or
            // lang="" attribtue from snapshots.
            NonTSPseudoClass::Lang(ref lang_arg) => {
                return self.element.match_element_lang(Some(self.get_lang()), lang_arg);
            }

            _ => {}
        }

        let flag = pseudo_class.state_flag();
        if flag.is_empty() {
            return self.element.match_non_ts_pseudo_class(
                pseudo_class,
                context,
                relevant_link,
                &mut |_, _| {},
            )
        }
        match self.snapshot().and_then(|s| s.state()) {
            Some(snapshot_state) => snapshot_state.intersects(flag),
            None => {
                self.element.match_non_ts_pseudo_class(
                    pseudo_class,
                    context,
                    relevant_link,
                    &mut |_, _| {},
                )
            }
        }
    }

    fn match_pseudo_element(
        &self,
        pseudo_element: &PseudoElement,
        context: &mut MatchingContext<Self::Impl>,
    ) -> bool {
        self.element.match_pseudo_element(pseudo_element, context)
    }

    fn is_link(&self) -> bool {
        self.element.is_link()
    }

    fn opaque(&self) -> OpaqueElement {
        self.element.opaque()
    }

    fn parent_element(&self) -> Option<Self> {
        self.element.parent_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn first_child_element(&self) -> Option<Self> {
        self.element.first_child_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn last_child_element(&self) -> Option<Self> {
        self.element.last_child_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn prev_sibling_element(&self) -> Option<Self> {
        self.element.prev_sibling_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn next_sibling_element(&self) -> Option<Self> {
        self.element.next_sibling_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn is_html_element_in_html_document(&self) -> bool {
        self.element.is_html_element_in_html_document()
    }

    fn get_local_name(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName {
        self.element.get_local_name()
    }

    fn get_namespace(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl {
        self.element.get_namespace()
    }

    fn attr_matches(&self,
                    ns: &NamespaceConstraint<&Namespace>,
                    local_name: &LocalName,
                    operation: &AttrSelectorOperation<&AttrValue>)
                    -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.attr_matches(ns, local_name, operation)
            }
            _ => self.element.attr_matches(ns, local_name, operation)
        }
    }

    fn has_id(&self, id: &Atom, case_sensitivity: CaseSensitivity) -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.id_attr().map_or(false, |atom| case_sensitivity.eq_atom(&atom, id))
            }
            _ => self.element.has_id(id, case_sensitivity)
        }
    }

    fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
        match self.snapshot() {
            Some(snapshot) if snapshot.has_attrs() => {
                snapshot.has_class(name, case_sensitivity)
            }
            _ => self.element.has_class(name, case_sensitivity)
        }
    }

    fn is_empty(&self) -> bool {
        self.element.is_empty()
    }

    fn is_root(&self) -> bool {
        self.element.is_root()
    }

    fn pseudo_element_originating_element(&self) -> Option<Self> {
        self.element.pseudo_element_originating_element()
            .map(|e| ElementWrapper::new(e, self.snapshot_map))
    }

    fn blocks_ancestor_combinators(&self) -> bool {
        self.element.blocks_ancestor_combinators()
    }
}
<|endoftext|>


<commit_before>use crate::common::util::*;

#[test]
fn test_with_tab() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-tab.txt").run();
    assert!(result.success);
    assert!(result.stdout.contains("        "));
    assert!(!result.stdout.contains("\t"));
}

#[test]
fn test_with_trailing_tab() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-trailing-tab.txt").run();
    assert!(result.success);
    assert!(result.stdout.contains("with tabs=>  "));
    assert!(!result.stdout.contains("\t"));
}

#[test]
fn test_with_trailing_tab_i() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-trailing-tab.txt").arg("-i").run();
    assert!(result.success);
    assert!(result.stdout.contains("        // with tabs=>\t"));
}

#[test]
fn test_with_tab_size() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-tab.txt").arg("--tabs=10").run();
    assert!(result.success);
    assert!(result.stdout.contains("          "));
}

#[test]
fn test_with_space() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-spaces.txt").run();
    assert!(result.success);
    assert!(result.stdout.contains("    return"));
}
<commit_msg>Expand: add test for multiple files<commit_after>use crate::common::util::*;

#[test]
fn test_with_tab() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-tab.txt").run();
    assert!(result.success);
    assert!(result.stdout.contains("        "));
    assert!(!result.stdout.contains("\t"));
}

#[test]
fn test_with_trailing_tab() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-trailing-tab.txt").run();
    assert!(result.success);
    assert!(result.stdout.contains("with tabs=>  "));
    assert!(!result.stdout.contains("\t"));
}

#[test]
fn test_with_trailing_tab_i() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-trailing-tab.txt").arg("-i").run();
    assert!(result.success);
    assert!(result.stdout.contains("        // with tabs=>\t"));
}

#[test]
fn test_with_tab_size() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-tab.txt").arg("--tabs=10").run();
    assert!(result.success);
    assert!(result.stdout.contains("          "));
}

#[test]
fn test_with_space() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-spaces.txt").run();
    assert!(result.success);
    assert!(result.stdout.contains("    return"));
}

#[test]
fn test_with_multiple_files() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.arg("with-spaces.txt").arg("with-tab.txt").run();
    assert!(result.success);
    assert!(result.stdout.contains("    return"));
    assert!(result.stdout.contains("        "));
}
<|endoftext|>


<commit_before>//! Common PPU rendering code (used by sprite and BG rendering)
//!
//! # Terminology
//!
//! * **Tile**/**Character**: A tile consists of 8x8 or 16x16 pixels worth of color indices and is
//!   what makes up both sprites and backgrounds. Sprites are always made up of 8x8 tiles, while
//!   backgrounds can use 16x16 pixel tiles by setting the appropriate bit in `BGMODE ($2105)`.
//! * **Background**: A background is a big, connected layer of tiles that can (only) be moved as a
//!   unit. Depending on the background mode, between 1 and 4 BG layers can be used, each with
//!   between 4 and 256 colors.
//! * **Sprite**: A sprite is an independently movable object up to 64x64 pixels in size. Sprites
//!   always use 8x8 tiles and 16 colors, while each sprite can use a different palette. Sprites can
//!   not be rotated (rotating objects in games are either prerendered or make use of BG mode 7,
//!   which allows full matrix transformations on the layer).
//! * **Name table**/**Character table**/**Character map**: These tables store tile data: Maps of
//!   color indices to use for the tile's pixels. Sprites and all background modes except mode 7
//!   store the color indices in "bitplanes", which makes their decoding tricky: A bitplane stores 1
//!   bit for every pixel of the tile. Two bitplanes are interleaved: Bitplane 0 is stored in the
//!   low byte, while bitplane 1 is stored in the high byte.
//! * **Tile map**: Backgrounds consist of 1, 2 or 4 tile maps, each storing data for 32x32 tiles.
//!   For each tile on the background, the tile map stores the tile's priority and H/V flip bits,
//!   the palette, and the tile number. If 16x16 tiles are enabled, each entry in the tile map
//!   stores data for a 16x16 tile consisting of 4 8x8 tiles: `TILE`, `TILE+1`, `TILE+16` and
//!   `TILE+17`, where `TILE` is the stored tile number.

use super::{Ppu, Rgb};

/// An enum of all layers a pixel can come from
enum Layer {
    Bg1,
    Bg2,
    Bg3,
    Bg4,
    Obj,
    Backdrop,
}

/// Rendering
impl Ppu {
    /// Get the configured sprite size in pixels. If `size_toggle` is `false`, gets the size of
    /// small sprites, otherwise gets the size of large sprites (OAM size bit set).
    pub fn obj_size(&self, size_toggle: bool) -> (u8, u8) {
        match self.obsel >> 5 & 0b111 {
            0b000 => if !size_toggle {(8,8)} else {(16,16)},
            0b001 => if !size_toggle {(8,8)} else {(32,32)},
            0b010 => if !size_toggle {(8,8)} else {(64,64)},
            0b011 => if !size_toggle {(16,16)} else {(32,32)},
            0b100 => if !size_toggle {(16,16)} else {(64,64)},
            0b101 => if !size_toggle {(32,32)} else {(64,64)},

            0b110 => if !size_toggle {(16,32)} else {(32,64)},
            0b111 => if !size_toggle {(16,32)} else {(32,32)},
            _ => unreachable!(),
        }
    }

    /// Returns the active BG mode (0-7).
    pub fn bg_mode(&self) -> u8 { self.bgmode & 0b111 }

    /// Returns the backdrop color used as a default color (with color math applied, if enabled).
    fn backdrop_color(&self) -> Rgb {
        // TODO: Color math
        self.cgram.get_color(0)
    }

    /// Renders a "raw" pixel (not doing color math), and returns the color and the layer it came
    /// from.
    ///
    /// If `sub` is true, fetches the pixel from the subscreen. Otherwise, the main screen is used.
    fn get_raw_pixel(&mut self, subscreen: bool) -> (Rgb, Layer) {
        macro_rules! e {
            ( $e:expr ) => ( $e );
        }

        macro_rules! bglayer {
            ( 1 ) => { Layer::Bg1 };
            ( 2 ) => { Layer::Bg2 };
            ( 3 ) => { Layer::Bg3 };
            ( 4 ) => { Layer::Bg4 };
        }

        // This macro gets the current pixel from a tile with given priority in the given layer.
        // If the pixel is non-transparent, it will return its RGB value (after applying color
        // math). If it is transparent, it will do nothing (ie. the code following this macro is
        // executed).
        macro_rules! try_layer {
            ( Sprites with priority $prio:tt ) => {
                if let Some(rgb) = self.maybe_draw_sprite_pixel(e!($prio), subscreen) {
                    return (rgb, Layer::Obj);
                }
            };
            ( BG $bg:tt tiles with priority $prio:tt ) => {
                if let Some(rgb) = self.lookup_bg_color(e!($bg), e!($prio), subscreen) {
                    return (rgb, bglayer!($bg));
                }
            };
        }

        match self.bg_mode() {
            0 => {
                // I love macros <3
                try_layer!(Sprites with priority 3);
                try_layer!(BG 1 tiles with priority 1);
                try_layer!(BG 2 tiles with priority 1);
                try_layer!(Sprites with priority 2);
                try_layer!(BG 1 tiles with priority 0);
                try_layer!(BG 2 tiles with priority 0);
                try_layer!(Sprites with priority 1);
                try_layer!(BG 3 tiles with priority 1);
                try_layer!(BG 4 tiles with priority 1);
                try_layer!(Sprites with priority 0);
                try_layer!(BG 3 tiles with priority 0);
                try_layer!(BG 4 tiles with priority 0);
            }
            1 => {
                if self.bgmode & 0x08 != 0 { try_layer!(BG 3 tiles with priority 1); }
                try_layer!(Sprites with priority 3);
                try_layer!(BG 1 tiles with priority 1);
                try_layer!(BG 2 tiles with priority 1);
                try_layer!(Sprites with priority 2);
                try_layer!(BG 1 tiles with priority 0);
                try_layer!(BG 2 tiles with priority 0);
                try_layer!(Sprites with priority 1);
                if self.bgmode & 0x08 == 0 { try_layer!(BG 3 tiles with priority 1); }
                try_layer!(Sprites with priority 0);
                try_layer!(BG 3 tiles with priority 0);
            }
            2 ... 5 => {
                // FIXME Do the background priorities differ here?
                try_layer!(Sprites with priority 3);
                try_layer!(BG 1 tiles with priority 1);
                try_layer!(Sprites with priority 2);
                try_layer!(BG 2 tiles with priority 1);
                try_layer!(Sprites with priority 1);
                try_layer!(BG 1 tiles with priority 0);
                try_layer!(Sprites with priority 0);
                try_layer!(BG 2 tiles with priority 0);
            }
            6 => {
                try_layer!(Sprites with priority 3);
                try_layer!(BG 1 tiles with priority 1);
                try_layer!(Sprites with priority 2);
                try_layer!(Sprites with priority 1);
                try_layer!(BG 1 tiles with priority 0);
                try_layer!(Sprites with priority 0);
            }
            7 => panic!("NYI: BG mode 7"),
            _ => unreachable!(),
        }

        (self.backdrop_color(), Layer::Backdrop)
    }

    /// Main rendering entry point. Renders the current pixel and returns its color. Assumes that
    /// the current pixel is on the screen.
    pub fn render_pixel(&mut self) -> Rgb {
        assert!(self.x < super::SCREEN_WIDTH as u16);
        assert!(self.scanline < super::SCREEN_HEIGHT as u16);

        if self.forced_blank() {
            return Rgb {r: 0, g: 0, b: 0};
        }

        if self.x == 0 && self.scanline == 0 {
            // Sprite overflow flags are reset "at the end of VBlank"
            // FIXME Is this correct or is the time wrong?
            self.range_over = false;
            self.time_over = false;

            trace!("New frame. BG mode {}, layers enabled: {:05b}, sprites are {:?} or {:?}",
                self.bg_mode(),
                self.tm & 0x1f,
                self.obj_size(false),
                self.obj_size(true));
        }

        if self.x == 0 {
            // Entered new scanline.
            self.collect_sprite_data_for_scanline();
        }

        self.get_raw_pixel(false).0
    }

    /// Reads character data for a pixel and returns the palette index stored in the bitplanes.
    ///
    /// # Parameters
    /// * `bitplane_count`: Number of bitplanes (must be even)
    /// * `start_addr`: Address of the first bitplane (or the first 2)
    /// * `tile_size`: 8 or 16
    /// * `(x, y)`: Offset inside the tile (`0-7` or `0-15`, depending on the tile size)
    /// * `(vflip, hflip)`: Flip this tile vertically (top and down are flipped) or horizontally
    ///   (left and right are flipped)
    pub fn read_chr_entry(&self,
                          bitplane_count: u8,
                          start_addr: u16,
                          tile_size: u8,
                          (x, y): (u8, u8),
                          (vflip, hflip): (bool, bool)) -> u8 {
        // 2 bitplanes are stored interleaved with each other, so there can only be an even number
        debug_assert!(bitplane_count & 1 == 0, "odd bitplane count");
        debug_assert!(x <= 7 || (x <= 15 && tile_size == 16), "invalid x value: {}", x);
        debug_assert!(y <= 7 || (y <= 15 && tile_size == 16), "invalid y value: {}", y);
        debug_assert!(tile_size == 8, "non-8x8 tiles unsupported"); // FIXME support 16x16 tiles
        let bitplane_pairs = bitplane_count >> 1;

        // Flip coordinates, if necessary
        let x = if hflip { tile_size - x - 1 } else { x };
        let y = if vflip { tile_size - y - 1 } else { y };

        let mut palette_index = 0u8;
        for i in 0..bitplane_pairs {
            let bitplane_bits = self.read_2_bitplanes(
                start_addr + i as u16 * 16, // 16 Bytes per pair of bitplanes
                (x, y));
            palette_index = palette_index | (bitplane_bits << (2 * i));
        }

        palette_index
    }

    /// Reads 2 bits of the given coordinate within the bitplane's tile from 2 interleaved
    /// bitplanes.
    ///
    /// # Parameters
    /// * `bitplanes_start`: Start address of the bitplanes
    /// * `(x_off, y_off)`: Offset into the tile (`0-7`)
    fn read_2_bitplanes(&self, bitplanes_start: u16, (x_off, y_off): (u8, u8)) -> u8 {
        // Bit 0 in low bytes, bit 1 in high bytes
        let lo = self.vram[bitplanes_start + y_off as u16 * 2];
        let hi = self.vram[bitplanes_start + y_off as u16 * 2 + 1];
        // X values in a byte: 01234567
        let bit0 = (lo >> (7 - x_off)) & 1;
        let bit1 = (hi >> (7 - x_off)) & 1;

        (bit1 << 1) | bit0
    }
}
<commit_msg>First attempt at color math and subscreen rendering<commit_after>//! Common PPU rendering code (used by sprite and BG rendering)
//!
//! # Terminology
//!
//! * **Tile**/**Character**: A tile consists of 8x8 or 16x16 pixels worth of color indices and is
//!   what makes up both sprites and backgrounds. Sprites are always made up of 8x8 tiles, while
//!   backgrounds can use 16x16 pixel tiles by setting the appropriate bit in `BGMODE ($2105)`.
//! * **Background**: A background is a big, connected layer of tiles that can (only) be moved as a
//!   unit. Depending on the background mode, between 1 and 4 BG layers can be used, each with
//!   between 4 and 256 colors.
//! * **Sprite**: A sprite is an independently movable object up to 64x64 pixels in size. Sprites
//!   always use 8x8 tiles and 16 colors, while each sprite can use a different palette. Sprites can
//!   not be rotated (rotating objects in games are either prerendered or make use of BG mode 7,
//!   which allows full matrix transformations on the layer).
//! * **Name table**/**Character table**/**Character map**: These tables store tile data: Maps of
//!   color indices to use for the tile's pixels. Sprites and all background modes except mode 7
//!   store the color indices in "bitplanes", which makes their decoding tricky: A bitplane stores 1
//!   bit for every pixel of the tile. Two bitplanes are interleaved: Bitplane 0 is stored in the
//!   low byte, while bitplane 1 is stored in the high byte.
//! * **Tile map**: Backgrounds consist of 1, 2 or 4 tile maps, each storing data for 32x32 tiles.
//!   For each tile on the background, the tile map stores the tile's priority and H/V flip bits,
//!   the palette, and the tile number. If 16x16 tiles are enabled, each entry in the tile map
//!   stores data for a 16x16 tile consisting of 4 8x8 tiles: `TILE`, `TILE+1`, `TILE+16` and
//!   `TILE+17`, where `TILE` is the stored tile number.

use super::{Ppu, Rgb};

/// An enum of all layers a pixel can come from
enum Layer {
    Bg1 = 0,
    Bg2 = 1,
    Bg3 = 2,
    Bg4 = 3,
    Obj = 4,
    Backdrop = 5,
}

/// Rendering
impl Ppu {
    /// Get the configured sprite size in pixels. If `size_toggle` is `false`, gets the size of
    /// small sprites, otherwise gets the size of large sprites (OAM size bit set).
    pub fn obj_size(&self, size_toggle: bool) -> (u8, u8) {
        match self.obsel >> 5 & 0b111 {
            0b000 => if !size_toggle {(8,8)} else {(16,16)},
            0b001 => if !size_toggle {(8,8)} else {(32,32)},
            0b010 => if !size_toggle {(8,8)} else {(64,64)},
            0b011 => if !size_toggle {(16,16)} else {(32,32)},
            0b100 => if !size_toggle {(16,16)} else {(64,64)},
            0b101 => if !size_toggle {(32,32)} else {(64,64)},

            0b110 => if !size_toggle {(16,32)} else {(32,64)},
            0b111 => if !size_toggle {(16,32)} else {(32,32)},
            _ => unreachable!(),
        }
    }

    /// Returns the active BG mode (0-7).
    pub fn bg_mode(&self) -> u8 { self.bgmode & 0b111 }

    /// Returns the backdrop color used as a default color (with color math applied, if enabled).
    fn backdrop_color(&self) -> Rgb {
        // TODO: Color math
        self.cgram.get_color(0)
    }

    /// Renders a "raw" pixel (not doing color math), and returns the color and the layer it came
    /// from.
    ///
    /// If `sub` is true, fetches the pixel from the subscreen. Otherwise, the main screen is used.
    fn get_raw_pixel(&mut self, subscreen: bool) -> (Rgb, Layer) {
        macro_rules! e {
            ( $e:expr ) => ( $e );
        }

        macro_rules! bglayer {
            ( 1 ) => { Layer::Bg1 };
            ( 2 ) => { Layer::Bg2 };
            ( 3 ) => { Layer::Bg3 };
            ( 4 ) => { Layer::Bg4 };
        }

        // This macro gets the current pixel from a tile with given priority in the given layer.
        // If the pixel is non-transparent, it will return its RGB value (after applying color
        // math). If it is transparent, it will do nothing (ie. the code following this macro is
        // executed).
        macro_rules! try_layer {
            ( Sprites with priority $prio:tt ) => {
                if let Some(rgb) = self.maybe_draw_sprite_pixel(e!($prio), subscreen) {
                    return (rgb, Layer::Obj);
                }
            };
            ( BG $bg:tt tiles with priority $prio:tt ) => {
                if let Some(rgb) = self.lookup_bg_color(e!($bg), e!($prio), subscreen) {
                    return (rgb, bglayer!($bg));
                }
            };
        }

        match self.bg_mode() {
            0 => {
                // I love macros <3
                try_layer!(Sprites with priority 3);
                try_layer!(BG 1 tiles with priority 1);
                try_layer!(BG 2 tiles with priority 1);
                try_layer!(Sprites with priority 2);
                try_layer!(BG 1 tiles with priority 0);
                try_layer!(BG 2 tiles with priority 0);
                try_layer!(Sprites with priority 1);
                try_layer!(BG 3 tiles with priority 1);
                try_layer!(BG 4 tiles with priority 1);
                try_layer!(Sprites with priority 0);
                try_layer!(BG 3 tiles with priority 0);
                try_layer!(BG 4 tiles with priority 0);
            }
            1 => {
                if self.bgmode & 0x08 != 0 { try_layer!(BG 3 tiles with priority 1); }
                try_layer!(Sprites with priority 3);
                try_layer!(BG 1 tiles with priority 1);
                try_layer!(BG 2 tiles with priority 1);
                try_layer!(Sprites with priority 2);
                try_layer!(BG 1 tiles with priority 0);
                try_layer!(BG 2 tiles with priority 0);
                try_layer!(Sprites with priority 1);
                if self.bgmode & 0x08 == 0 { try_layer!(BG 3 tiles with priority 1); }
                try_layer!(Sprites with priority 0);
                try_layer!(BG 3 tiles with priority 0);
            }
            2 ... 5 => {
                // FIXME Do the background priorities differ here?
                try_layer!(Sprites with priority 3);
                try_layer!(BG 1 tiles with priority 1);
                try_layer!(Sprites with priority 2);
                try_layer!(BG 2 tiles with priority 1);
                try_layer!(Sprites with priority 1);
                try_layer!(BG 1 tiles with priority 0);
                try_layer!(Sprites with priority 0);
                try_layer!(BG 2 tiles with priority 0);
            }
            6 => {
                try_layer!(Sprites with priority 3);
                try_layer!(BG 1 tiles with priority 1);
                try_layer!(Sprites with priority 2);
                try_layer!(Sprites with priority 1);
                try_layer!(BG 1 tiles with priority 0);
                try_layer!(Sprites with priority 0);
            }
            7 => panic!("NYI: BG mode 7"),
            _ => unreachable!(),
        }

        (self.backdrop_color(), Layer::Backdrop)
    }

    fn color_math_enabled(&self, layer: Layer) -> bool {
        // FIXME Take color window and CGWSEL into account
        self.cgadsub & (1 << layer as u8) != 0
    }

    /// Main rendering entry point. Renders the current pixel and returns its color. Assumes that
    /// the current pixel is on the screen.
    pub fn render_pixel(&mut self) -> Rgb {
        assert!(self.x < super::SCREEN_WIDTH as u16);
        assert!(self.scanline < super::SCREEN_HEIGHT as u16);

        if self.forced_blank() {
            return Rgb {r: 0, g: 0, b: 0};
        }

        if self.x == 0 && self.scanline == 0 {
            // Sprite overflow flags are reset "at the end of VBlank"
            // FIXME Is this correct or is the time wrong?
            self.range_over = false;
            self.time_over = false;

            trace!("New frame. BG mode {}, layers enabled: {:05b}, sprites are {:?} or {:?}",
                self.bg_mode(),
                self.tm & 0x1f,
                self.obj_size(false),
                self.obj_size(true));
        }

        if self.x == 0 {
            // Entered new scanline.
            self.collect_sprite_data_for_scanline();
        }

        let (main_pix_color, main_pix_layer) = self.get_raw_pixel(false);
        if self.color_math_enabled(main_pix_layer) {
            let math_color = if self.cgwsel & 0x02 == 0 {
                // Fixed color
                // FIXME: This is 5-bit RGB, which is totally wrong. Is it enough to do the normal
                // adjustment?
                Rgb {
                    r: self.coldata_r,
                    g: self.coldata_g,
                    b: self.coldata_b,
                }
            } else {
                // Subscreen
                self.get_raw_pixel(true).0
            };

            if self.cgadsub & 0x80 == 0 {
                // Add
                // FIXME impl Add/Sub for Rgb ?
                Rgb {
                    r: main_pix_color.r + math_color.r,
                    g: main_pix_color.g + math_color.g,
                    b: main_pix_color.b + math_color.b,
                }
            } else {
                // Subtract
                Rgb {
                    r: main_pix_color.r - math_color.r,
                    g: main_pix_color.g - math_color.g,
                    b: main_pix_color.b - math_color.b,
                }
            }
        } else {
            // No color math
            main_pix_color
        }
    }

    /// Reads character data for a pixel and returns the palette index stored in the bitplanes.
    ///
    /// # Parameters
    /// * `bitplane_count`: Number of bitplanes (must be even)
    /// * `start_addr`: Address of the first bitplane (or the first 2)
    /// * `tile_size`: 8 or 16
    /// * `(x, y)`: Offset inside the tile (`0-7` or `0-15`, depending on the tile size)
    /// * `(vflip, hflip)`: Flip this tile vertically (top and down are flipped) or horizontally
    ///   (left and right are flipped)
    pub fn read_chr_entry(&self,
                          bitplane_count: u8,
                          start_addr: u16,
                          tile_size: u8,
                          (x, y): (u8, u8),
                          (vflip, hflip): (bool, bool)) -> u8 {
        // 2 bitplanes are stored interleaved with each other, so there can only be an even number
        debug_assert!(bitplane_count & 1 == 0, "odd bitplane count");
        debug_assert!(x <= 7 || (x <= 15 && tile_size == 16), "invalid x value: {}", x);
        debug_assert!(y <= 7 || (y <= 15 && tile_size == 16), "invalid y value: {}", y);
        debug_assert!(tile_size == 8, "non-8x8 tiles unsupported"); // FIXME support 16x16 tiles
        let bitplane_pairs = bitplane_count >> 1;

        // Flip coordinates, if necessary
        let x = if hflip { tile_size - x - 1 } else { x };
        let y = if vflip { tile_size - y - 1 } else { y };

        let mut palette_index = 0u8;
        for i in 0..bitplane_pairs {
            let bitplane_bits = self.read_2_bitplanes(
                start_addr + i as u16 * 16, // 16 Bytes per pair of bitplanes
                (x, y));
            palette_index = palette_index | (bitplane_bits << (2 * i));
        }

        palette_index
    }

    /// Reads 2 bits of the given coordinate within the bitplane's tile from 2 interleaved
    /// bitplanes.
    ///
    /// # Parameters
    /// * `bitplanes_start`: Start address of the bitplanes
    /// * `(x_off, y_off)`: Offset into the tile (`0-7`)
    fn read_2_bitplanes(&self, bitplanes_start: u16, (x_off, y_off): (u8, u8)) -> u8 {
        // Bit 0 in low bytes, bit 1 in high bytes
        let lo = self.vram[bitplanes_start + y_off as u16 * 2];
        let hi = self.vram[bitplanes_start + y_off as u16 * 2 + 1];
        // X values in a byte: 01234567
        let bit0 = (lo >> (7 - x_off)) & 1;
        let bit1 = (hi >> (7 - x_off)) & 1;

        (bit1 << 1) | bit0
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! The Butterfly client library.
//!
//! This will connect to a given butterfly members `Pull` thread, and inject a rumor.

use habitat_core::crypto::SymKey;
use habitat_core::service::ServiceGroup;
use habitat_net::server::ZMQ_CONTEXT;
use zmq;

use message;
use rumor::Rumor;
use rumor::service_config::ServiceConfig;
use rumor::service_file::ServiceFile;
use error::{Result, Error};

/// Holds a ZMQ Push socket, and an optional ring encryption key.
pub struct Client {
    socket: zmq::Socket,
    ring_key: Option<SymKey>,
}

impl Client {
    /// Connect this client to the address, and optionally encrypt the traffic.
    pub fn new<A: ToString>(addr: A, ring_key: Option<SymKey>) -> Result<Client> {
        let mut socket = (**ZMQ_CONTEXT)
            .as_mut()
            .socket(zmq::PUSH)
            .expect("Failure to create the ZMQ push socket");
        socket.set_linger(1000)
            .expect("Failure to set the ZMQ push socket to not linger");
        socket.set_tcp_keepalive(0)
            .expect("Failure to set the ZMQ push socket to not use keepalive");
        socket.set_immediate(true)
            .expect("Failure to set the ZMQ push socket to immediate");
        socket.set_sndhwm(1000)
            .expect("Failure to set the ZMQ push socket hwm");
        socket.set_sndtimeo(500)
            .expect("Failure to set the ZMQ send timeout");
        let to_addr = format!("tcp://{}", addr.to_string());
        try!(socket.connect(&to_addr).map_err(Error::ZmqConnectError));
        Ok(Client {
            socket: socket,
            ring_key: ring_key,
        })
    }

    /// Create a service configuration and send it to the server.
    pub fn send_service_config(&mut self,
                               service_group: ServiceGroup,
                               incarnation: u64,
                               config: Vec<u8>,
                               encrypted: bool)
                               -> Result<()> {
        let mut sc = ServiceConfig::new("butterflyclient", service_group, config);
        sc.set_incarnation(incarnation);
        sc.set_encrypted(encrypted);
        self.send(sc)
    }

    /// Create a service file and send it to the server.
    pub fn send_service_file<S: Into<String>>(&mut self,
                                              service_group: ServiceGroup,
                                              filename: S,
                                              incarnation: u64,
                                              body: Vec<u8>,
                                              encrypted: bool)
                                              -> Result<()> {
        let mut sf = ServiceFile::new("butterflyclient", service_group, filename, body);
        sf.set_incarnation(incarnation);
        sf.set_encrypted(encrypted);
        self.send(sf)
    }

    /// Send any `Rumor` to the server.
    pub fn send<T: Rumor>(&mut self, rumor: T) -> Result<()> {
        let bytes = try!(rumor.write_to_bytes());
        let wire_msg = try!(message::generate_wire(bytes, &self.ring_key));
        self.socket.send(&wire_msg, 0).map_err(Error::ZmqSendError)
    }
}
<commit_msg>[hab-butterfly] Update zmq socket linger to `-1`.<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! The Butterfly client library.
//!
//! This will connect to a given butterfly members `Pull` thread, and inject a rumor.

use habitat_core::crypto::SymKey;
use habitat_core::service::ServiceGroup;
use habitat_net::server::ZMQ_CONTEXT;
use zmq;

use message;
use rumor::Rumor;
use rumor::service_config::ServiceConfig;
use rumor::service_file::ServiceFile;
use error::{Result, Error};

/// Holds a ZMQ Push socket, and an optional ring encryption key.
pub struct Client {
    socket: zmq::Socket,
    ring_key: Option<SymKey>,
}

impl Client {
    /// Connect this client to the address, and optionally encrypt the traffic.
    pub fn new<A: ToString>(addr: A, ring_key: Option<SymKey>) -> Result<Client> {
        let mut socket = (**ZMQ_CONTEXT)
            .as_mut()
            .socket(zmq::PUSH)
            .expect("Failure to create the ZMQ push socket");
        socket.set_linger(-1)
            .expect("Failure to set the ZMQ push socket to not linger");
        socket.set_tcp_keepalive(0)
            .expect("Failure to set the ZMQ push socket to not use keepalive");
        socket.set_immediate(true)
            .expect("Failure to set the ZMQ push socket to immediate");
        socket.set_sndhwm(1000)
            .expect("Failure to set the ZMQ push socket hwm");
        socket.set_sndtimeo(500)
            .expect("Failure to set the ZMQ send timeout");
        let to_addr = format!("tcp://{}", addr.to_string());
        try!(socket.connect(&to_addr).map_err(Error::ZmqConnectError));
        Ok(Client {
            socket: socket,
            ring_key: ring_key,
        })
    }

    /// Create a service configuration and send it to the server.
    pub fn send_service_config(&mut self,
                               service_group: ServiceGroup,
                               incarnation: u64,
                               config: Vec<u8>,
                               encrypted: bool)
                               -> Result<()> {
        let mut sc = ServiceConfig::new("butterflyclient", service_group, config);
        sc.set_incarnation(incarnation);
        sc.set_encrypted(encrypted);
        self.send(sc)
    }

    /// Create a service file and send it to the server.
    pub fn send_service_file<S: Into<String>>(&mut self,
                                              service_group: ServiceGroup,
                                              filename: S,
                                              incarnation: u64,
                                              body: Vec<u8>,
                                              encrypted: bool)
                                              -> Result<()> {
        let mut sf = ServiceFile::new("butterflyclient", service_group, filename, body);
        sf.set_incarnation(incarnation);
        sf.set_encrypted(encrypted);
        self.send(sf)
    }

    /// Send any `Rumor` to the server.
    pub fn send<T: Rumor>(&mut self, rumor: T) -> Result<()> {
        let bytes = try!(rumor.write_to_bytes());
        let wire_msg = try!(message::generate_wire(bytes, &self.ring_key));
        self.socket.send(&wire_msg, 0).map_err(Error::ZmqSendError)
    }
}
<|endoftext|>


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

use rustc::hir::def_id::DefId;
use rustc::lint::{LateContext, LintContext};
use syntax::ast;
use syntax::codemap::{ExpnFormat, Span};
use syntax::ptr::P;

/// Matches a type with a provided string, and returns its type parameters if successful
pub fn match_ty_unwrap<'a>(ty: &'a ast::Ty, segments: &[&str]) -> Option<&'a [P<ast::Ty>]> {
    match ty.node {
        ast::TyKind::Path(_, ast::Path { segments: ref seg, .. }) => {
            // So hir::Path isn't the full path, just the tokens that were provided.
            // I could muck around with the maps and find the full path
            // however the more efficient way is to simply reverse the iterators and zip them
            // which will compare them in reverse until one of them runs out of segments
            if seg.iter().rev().zip(segments.iter().rev()).all(|(a, b)| &*a.identifier.name.as_str() == *b) {
                match seg.last() {
                    Some(&ast::PathSegment { parameters: Some(ref params), .. }) => {
                        match **params {
                            ast::PathParameters::AngleBracketed(ref a) => Some(&a.types),

                            // `Foo(A,B) -> C`
                            ast::PathParameters::Parenthesized(_) => None,
                        }
                    }
                    Some(&ast::PathSegment { parameters: None, .. }) => Some(&[]),
                    None => None,
                }
            } else {
                None
            }
        },
        _ => None
    }
}

/// check if a DefId's path matches the given absolute type path
/// usage e.g. with
/// `match_def_path(cx, id, &["core", "option", "Option"])`
pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool {
    let krate = &cx.tcx.crate_name(def_id.krate);
    if krate != &path[0] {
        return false;
    }

    let path = &path[1..];
    let other = cx.tcx.def_path(def_id).data;

    if other.len() != path.len() {
        return false;
    }

    other.into_iter()
         .map(|e| e.data)
         .zip(path)
         .all(|(nm, p)| &*nm.as_interned_str() == *p)
}

pub fn in_derive_expn(cx: &LateContext, span: Span) -> bool {
    cx.sess().codemap().with_expn_info(span.expn_id,
            |info| {
                if let Some(i) = info {
                    if let ExpnFormat::MacroAttribute(n) = i.callee.format {
                        if n.as_str().contains("derive") {
                            true
                        } else { false }
                    } else { false }
                } else { false }
            })
}
<commit_msg>Remove unused function match_ty_unwrap<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/. */

use rustc::hir::def_id::DefId;
use rustc::lint::{LateContext, LintContext};
use syntax::codemap::{ExpnFormat, Span};

/// check if a DefId's path matches the given absolute type path
/// usage e.g. with
/// `match_def_path(cx, id, &["core", "option", "Option"])`
pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool {
    let krate = &cx.tcx.crate_name(def_id.krate);
    if krate != &path[0] {
        return false;
    }

    let path = &path[1..];
    let other = cx.tcx.def_path(def_id).data;

    if other.len() != path.len() {
        return false;
    }

    other.into_iter()
         .map(|e| e.data)
         .zip(path)
         .all(|(nm, p)| &*nm.as_interned_str() == *p)
}

pub fn in_derive_expn(cx: &LateContext, span: Span) -> bool {
    cx.sess().codemap().with_expn_info(span.expn_id,
            |info| {
                if let Some(i) = info {
                    if let ExpnFormat::MacroAttribute(n) = i.callee.format {
                        if n.as_str().contains("derive") {
                            true
                        } else { false }
                    } else { false }
                } else { false }
            })
}
<|endoftext|>


<commit_before>//! This module defines the metadata on devices and services.
//!
//! Note that all the data structures in this module represent
//! snapshots of subsets of the devices available. None of these data
//! structures are live, so there is always the possibility that
//! devices may have been added or removed from the FoxBox by the time
//! these data structures are read.

use values::*;

extern crate chrono;
use serde::ser::Serializer;
use serde::de::{Deserializer, Error};

/// The unique Id of a node on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NodeId(String);
impl NodeId {
    pub fn new(id: String) -> Self {
        NodeId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// Metadata on a node. A node is a device or collection of devices
/// that may offer services. The FoxBox itself a node offering
/// services such as a clock, communication with the user through her
/// smart devices, etc.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
    /// Tags describing the node.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications to find nodes and
    /// services.
    ///
    /// For instance, a user may set tag "entrance" to all nodes
    /// placed in the entrance of his house, or a tag "blue" to a node
    /// controlling blue lights. An adapter may set tags "plugged" or
    /// "battery" to devices that respectively depend on a plugged
    /// power source or on a battery.
    tags: Vec<String>,

    /// An id unique to this node.
    id: NodeId,

    /// Services connected directly to this node.
    inputs: Vec<Service<Input>>,
    outputs: Vec<Service<Output>>,
}

impl Node {
    /// Tags describing the node.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications.
    ///
    /// For instance "entrance".
    pub fn get_tags<'a>(&'a self) -> &'a Vec<String> {
        &self.tags
    }

    /// An id unique to this node.
    pub fn get_id<'a>(&'a self) -> &'a NodeId {
        &self.id
    }

    /// Input services connected directly to this node.
    pub fn get_inputs<'a>(&'a self) -> &'a Vec<Service<Input>> {
        &self.inputs
    }

    /// Output services connected directly to this node.
    pub fn get_outputs<'a>(&'a self) -> &'a Vec<Service<Output>> {
        &self.outputs
    }
}

/// The unique Id of a service on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ServiceId(String);
impl ServiceId {
    pub fn new(id: String) -> Self {
        ServiceId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// The kind of the service, i.e. a strongly-typed description of
/// _what_ the service can do. Used both for locating services
/// (e.g. "I need a clock" or "I need something that can provide
/// pictures") and for determining the data structure that these
/// services can provide or consume.
///
/// A number of service kinds are standardized, and provided as a set
/// of strongly-typed enum constructors. It is clear, however, that
/// many devices will offer services that cannot be described by
/// pre-existing constructors. For this purpose, this enumeration
/// offers a constructor `Extension`, designed to describe novel
/// services.
//
// Important: If you add constructors, don't forget to update `from_string`.
//
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ServiceKind {
    ///
    /// # No payload
    ///

    /// The service is ready. Used for instance once a countdown has
    /// reached completion.
    Ready,

    ///
    /// # Boolean
    ///

    /// The service is used to detect or decide whether some device
    /// is on or off.
    OnOff,

    /// The service is used to detect or decide whether some device
    /// is open or closed.
    OpenClosed,

    ///
    /// # Time
    ///

    /// The service is used to read or set the current absolute time.
    /// Used for instance to wait until a specific time and day before
    /// triggering an action, or to set the appropriate time on a new
    /// device.
    CurrentTime,

    /// The service is used to read or set the current time of day.
    /// Used for instance to trigger an action at a specific hour
    /// every day.
    CurrentTimeOfDay,

    /// The service is part of a countdown. This is the time
    /// remaining until the countdown is elapsed.
    RemainingTime,

    ///
    /// # Temperature
    ///

    Thermostat,
    ActualTemperature,

    /// TODO: Add more

    /// An operation of a kind that has not been standardized yet.
    Extension {
        /// The vendor. Used for namespacing purposes, to avoid
        /// confusing two incompatible extensions with similar
        /// names. For instance, "foxlink@mozilla.com".
        vendor: String,

        /// Identification of the adapter introducing this operation.
        /// Designed to aid with tracing and debugging.
        adapter: String,

        /// A string describing the nature of the value, designed to
        /// let applications discover the devices.
        ///
        /// Examples: `"GroundHumidity"`.
        kind: String,

        /// The data type of the value.
        typ: Type
    }
}

impl ServiceKind {
    /// Get the type of values used to communicate with this service.
    pub fn get_type(&self) -> Type {
        use self::ServiceKind::*;
        use values::Type::*;
        match *self {
            Ready => Unit,
            OnOff | OpenClosed => Bool,
            CurrentTime => TimeStamp,
            CurrentTimeOfDay | RemainingTime => Duration,
            Thermostat | ActualTemperature => Temperature,
            Extension { ref typ, ..} => typ.clone(),
        }
    }

    pub fn from_string(s: String) -> Option<Self> {
        use self::ServiceKind::*;
        match &*s {
            "Ready" => Some(Ready),
            "OnOff" => Some(OnOff),
            "OpenClosed" => Some(OpenClosed),
            "CurrentTime" => Some(CurrentTime),
            "CurrentTimeOfDay" => Some(CurrentTimeOfDay),
            "RemainingTime" => Some(RemainingTime),
            "Thermostat" => Some(Thermostat),
            "ActualTemperature" => Some(ActualTemperature),
            _ => None,
        }
    }
}

/// An input operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Input {
    /// The kind of value that can be obtained from this service.
    kind: ServiceKind,

    /// If `Some(duration)`, this service can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the service cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    #[serde(default)]
    poll: Option<ValDuration>,

    /// If `Some(duration)`, this service can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the service cannot send data to the FoxBox
    /// and needs to be polled.
    #[serde(default)]
    trigger: Option<ValDuration>,

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    updated: TimeStamp,
}

impl Input {
    /// The kind of value that can be obtained from this service.
    pub fn get_kind(&self) -> ServiceKind {
        self.kind.clone()
    }

    /// If `Some(duration)`, this service can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the service cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    pub fn get_poll(&self) -> Option<ValDuration> {
        self.poll.clone()
    }

    /// If `Some(duration)`, this service can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the service cannot send data to the FoxBox
    /// and needs to be polled.
    pub fn get_trigger(&self) -> Option<ValDuration> {
        self.trigger.clone()
    }

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    ///
    /// # Limitation
    ///
    /// This is *not* a live view.
    pub fn get_updated(&self) -> TimeStamp {
        self.updated.clone()
    }
}

/// An output operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Output {
    /// The kind of value that can be sent to this service.
    kind: ServiceKind,

    /// If `Some(duration)`, this service supports pushing,
    /// i.e. the FoxBox can send values.
    #[serde(default)]
    push: Option<ValDuration>,

    /// Date at which the latest value was sent to the service.
    updated: TimeStamp,
}

impl Output {
    /// The kind of value that can be sent to this service.
    pub fn get_kind(&self) -> ServiceKind {
        self.kind.clone()
    }

    /// If `Some(duration)`, this service supports pushing,
    /// i.e. the FoxBox can send values.
    pub fn get_push(&self) -> Option<ValDuration> {
        self.push.clone()
    }

    /// Date at which the latest value was sent.
    ///
    /// # Limitation
    ///
    /// This is *not* a live view.
    pub fn get_updated(&self) -> TimeStamp {
        self.updated.clone()
    }
}

/// An service represents a single place where data can enter or
/// leave a device. Note that services support either a single kind
/// of input or a single kind of output. Devices that support both
/// inputs or outputs, or several kinds of inputs, or several kinds of
/// outputs, are represented as nodes containing several services.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service<IO> {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup services for rules.
    ///
    /// For instance "entrance".
    #[serde(default)]
    tags: Vec<String>,

    /// An id unique to this service.
    id: ServiceId,

    /// The node owning this service.
    node: NodeId,

    /// The update mechanism for this service.
    mechanism: IO,

    /// The last time the device was seen.
    last_seen: TimeStamp,
}

impl<IO> Service<IO> {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup services for rules.
    ///
    /// For instance "entrance".
    pub fn get_tags<'a>(&'a self) -> &'a Vec<String> {
        &self.tags
    }

    /// An id unique to this service.
    pub fn get_id<'a>(&'a self) -> &'a ServiceId {
        &self.id
    }

    /// The node owning this service.
    pub fn get_node_id<'a>(&'a self) -> &'a NodeId {
        &self.node
    }

    /// The update mechanism for this service.
    pub fn get_mechanism<'a>(&'a self) -> &'a IO {
        &self.mechanism
    }

    /// The last time the device was seen.
    pub fn get_last_seen(&self) -> TimeStamp {
        self.last_seen.clone()
    }
}

<commit_msg>[fxbox/taxonomy] More serialization for Input/Output/IO<commit_after>//! This module defines the metadata on devices and services.
//!
//! Note that all the data structures in this module represent
//! snapshots of subsets of the devices available. None of these data
//! structures are live, so there is always the possibility that
//! devices may have been added or removed from the FoxBox by the time
//! these data structures are read.

use values::*;

extern crate chrono;
use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error};

/// The unique Id of a node on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NodeId(String);
impl NodeId {
    pub fn new(id: String) -> Self {
        NodeId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// Metadata on a node. A node is a device or collection of devices
/// that may offer services. The FoxBox itself a node offering
/// services such as a clock, communication with the user through her
/// smart devices, etc.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
    /// Tags describing the node.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications to find nodes and
    /// services.
    ///
    /// For instance, a user may set tag "entrance" to all nodes
    /// placed in the entrance of his house, or a tag "blue" to a node
    /// controlling blue lights. An adapter may set tags "plugged" or
    /// "battery" to devices that respectively depend on a plugged
    /// power source or on a battery.
    tags: Vec<String>,

    /// An id unique to this node.
    id: NodeId,

    /// Services connected directly to this node.
    inputs: Vec<Service<Input>>,
    outputs: Vec<Service<Output>>,
}

impl Node {
    /// Tags describing the node.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications.
    ///
    /// For instance "entrance".
    pub fn get_tags<'a>(&'a self) -> &'a Vec<String> {
        &self.tags
    }

    /// An id unique to this node.
    pub fn get_id<'a>(&'a self) -> &'a NodeId {
        &self.id
    }

    /// Input services connected directly to this node.
    pub fn get_inputs<'a>(&'a self) -> &'a Vec<Service<Input>> {
        &self.inputs
    }

    /// Output services connected directly to this node.
    pub fn get_outputs<'a>(&'a self) -> &'a Vec<Service<Output>> {
        &self.outputs
    }
}

/// The unique Id of a service on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ServiceId(String);
impl ServiceId {
    pub fn new(id: String) -> Self {
        ServiceId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// The kind of the service, i.e. a strongly-typed description of
/// _what_ the service can do. Used both for locating services
/// (e.g. "I need a clock" or "I need something that can provide
/// pictures") and for determining the data structure that these
/// services can provide or consume.
///
/// A number of service kinds are standardized, and provided as a set
/// of strongly-typed enum constructors. It is clear, however, that
/// many devices will offer services that cannot be described by
/// pre-existing constructors. For this purpose, this enumeration
/// offers a constructor `Extension`, designed to describe novel
/// services.
//
// Important: If you add constructors, don't forget to update `from_string`.
//
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ServiceKind {
    ///
    /// # No payload
    ///

    /// The service is ready. Used for instance once a countdown has
    /// reached completion.
    Ready,

    ///
    /// # Boolean
    ///

    /// The service is used to detect or decide whether some device
    /// is on or off.
    OnOff,

    /// The service is used to detect or decide whether some device
    /// is open or closed.
    OpenClosed,

    ///
    /// # Time
    ///

    /// The service is used to read or set the current absolute time.
    /// Used for instance to wait until a specific time and day before
    /// triggering an action, or to set the appropriate time on a new
    /// device.
    CurrentTime,

    /// The service is used to read or set the current time of day.
    /// Used for instance to trigger an action at a specific hour
    /// every day.
    CurrentTimeOfDay,

    /// The service is part of a countdown. This is the time
    /// remaining until the countdown is elapsed.
    RemainingTime,

    ///
    /// # Temperature
    ///

    Thermostat,
    ActualTemperature,

    /// TODO: Add more

    /// An operation of a kind that has not been standardized yet.
    Extension {
        /// The vendor. Used for namespacing purposes, to avoid
        /// confusing two incompatible extensions with similar
        /// names. For instance, "foxlink@mozilla.com".
        vendor: String,

        /// Identification of the adapter introducing this operation.
        /// Designed to aid with tracing and debugging.
        adapter: String,

        /// A string describing the nature of the value, designed to
        /// let applications discover the devices.
        ///
        /// Examples: `"GroundHumidity"`.
        kind: String,

        /// The data type of the value.
        typ: Type
    }
}

impl ServiceKind {
    /// Get the type of values used to communicate with this service.
    pub fn get_type(&self) -> Type {
        use self::ServiceKind::*;
        use values::Type::*;
        match *self {
            Ready => Unit,
            OnOff | OpenClosed => Bool,
            CurrentTime => TimeStamp,
            CurrentTimeOfDay | RemainingTime => Duration,
            Thermostat | ActualTemperature => Temperature,
            Extension { ref typ, ..} => typ.clone(),
        }
    }

    pub fn from_string(s: String) -> Option<Self> {
        use self::ServiceKind::*;
        match &*s {
            "Ready" => Some(Ready),
            "OnOff" => Some(OnOff),
            "OpenClosed" => Some(OpenClosed),
            "CurrentTime" => Some(CurrentTime),
            "CurrentTimeOfDay" => Some(CurrentTimeOfDay),
            "RemainingTime" => Some(RemainingTime),
            "Thermostat" => Some(Thermostat),
            "ActualTemperature" => Some(ActualTemperature),
            _ => None,
        }
    }
}

/// An input operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Input {
    /// The kind of value that can be obtained from this service.
    kind: ServiceKind,

    /// If `Some(duration)`, this service can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the service cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    #[serde(default)]
    poll: Option<ValDuration>,

    /// If `Some(duration)`, this service can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the service cannot send data to the FoxBox
    /// and needs to be polled.
    #[serde(default)]
    trigger: Option<ValDuration>,

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    updated: TimeStamp,
}
impl IOMechanism for Input {
}
impl Input {
    /// The kind of value that can be obtained from this service.
    pub fn get_kind(&self) -> ServiceKind {
        self.kind.clone()
    }

    /// If `Some(duration)`, this service can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the service cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    pub fn get_poll(&self) -> Option<ValDuration> {
        self.poll.clone()
    }

    /// If `Some(duration)`, this service can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the service cannot send data to the FoxBox
    /// and needs to be polled.
    pub fn get_trigger(&self) -> Option<ValDuration> {
        self.trigger.clone()
    }

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    ///
    /// # Limitation
    ///
    /// This is *not* a live view.
    pub fn get_updated(&self) -> TimeStamp {
        self.updated.clone()
    }
}

/// An output operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Output {
    /// The kind of value that can be sent to this service.
    kind: ServiceKind,

    /// If `Some(duration)`, this service supports pushing,
    /// i.e. the FoxBox can send values.
    #[serde(default)]
    push: Option<ValDuration>,

    /// Date at which the latest value was sent to the service.
    updated: TimeStamp,
}
impl IOMechanism for Output {
}
impl Output {
    /// The kind of value that can be sent to this service.
    pub fn get_kind(&self) -> ServiceKind {
        self.kind.clone()
    }

    /// If `Some(duration)`, this service supports pushing,
    /// i.e. the FoxBox can send values.
    pub fn get_push(&self) -> Option<ValDuration> {
        self.push.clone()
    }

    /// Date at which the latest value was sent.
    ///
    /// # Limitation
    ///
    /// This is *not* a live view.
    pub fn get_updated(&self) -> TimeStamp {
        self.updated.clone()
    }
}

/// An service represents a single place where data can enter or
/// leave a device. Note that services support either a single kind
/// of input or a single kind of output. Devices that support both
/// inputs or outputs, or several kinds of inputs, or several kinds of
/// outputs, are represented as nodes containing several services.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service<IO> where IO: IOMechanism {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup services for rules.
    ///
    /// For instance "entrance".
    #[serde(default)]
    tags: Vec<String>,

    /// An id unique to this service.
    id: ServiceId,

    /// The node owning this service.
    node: NodeId,

    /// The update mechanism for this service.
    mechanism: IO,

    /// The last time the device was seen.
    last_seen: TimeStamp,
}

impl<IO> Service<IO> where IO: IOMechanism {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup services for rules.
    ///
    /// For instance "entrance".
    pub fn get_tags<'a>(&'a self) -> &'a Vec<String> {
        &self.tags
    }

    /// An id unique to this service.
    pub fn get_id<'a>(&'a self) -> &'a ServiceId {
        &self.id
    }

    /// The node owning this service.
    pub fn get_node_id<'a>(&'a self) -> &'a NodeId {
        &self.node
    }

    /// The update mechanism for this service.
    pub fn get_mechanism<'a>(&'a self) -> &'a IO {
        &self.mechanism
    }

    /// The last time the device was seen.
    pub fn get_last_seen(&self) -> TimeStamp {
        self.last_seen.clone()
    }
}

/// A mechanism used for communicating between the application and the
/// service.
pub trait IOMechanism: Deserialize + Serialize {
}
<|endoftext|>


<commit_before>use std::ptr;
use std::os::win32::as_utf16_p;
use ll::*;

pub trait Window {
    fn hwnd(&self) -> HWND;
}

pub struct EmptyWindow {
    raw: HWND,
}

impl Window for EmptyWindow {
    fn hwnd(&self) -> HWND {
        self.raw
    }
}

pub fn null() -> EmptyWindow {
    EmptyWindow {
        raw: ptr::null(),
    }
}

pub trait WindowUtil {
    pub fn show(&self, cmd_show: int) -> bool;

    pub fn update(&self) -> bool;
}

impl<T: Window> WindowUtil for T {
    pub fn show(&self, cmd_show: int) -> bool {
        unsafe { user32::ShowWindow(self.hwnd(), cmd_show as c_int) as bool }
    }

    pub fn update(&self) -> bool {
        unsafe { user32::UpdateWindow(self.hwnd()) as bool }
    }
}

pub trait DialogUtil {
    pub fn message_box(&self, msg: &str, title: &str);
}

impl<T: Window> DialogUtil for T {
    pub fn message_box(&self, msg: &str, title: &str) {
        do as_utf16_p(msg) |msg_p| {
            do as_utf16_p(title) |title_p| {
                unsafe {
                    user32::MessageBoxW(self.hwnd(), msg_p, title_p, 0u32);
                }
            }
        }
    }
}
<commit_msg>make EmptyWindow empty<commit_after>use std::ptr;
use std::os::win32::as_utf16_p;
use ll::*;

pub trait Window {
    fn hwnd(&self) -> HWND;
}

pub struct EmptyWindow;

impl Window for EmptyWindow {
    fn hwnd(&self) -> HWND {
        ptr::null()
    }
}

pub fn null() -> EmptyWindow {
    EmptyWindow
}

pub trait WindowUtil {
    pub fn show(&self, cmd_show: int) -> bool;

    pub fn update(&self) -> bool;
}

impl<T: Window> WindowUtil for T {
    pub fn show(&self, cmd_show: int) -> bool {
        unsafe { user32::ShowWindow(self.hwnd(), cmd_show as c_int) as bool }
    }

    pub fn update(&self) -> bool {
        unsafe { user32::UpdateWindow(self.hwnd()) as bool }
    }
}

pub trait DialogUtil {
    pub fn message_box(&self, msg: &str, title: &str);
}

impl<T: Window> DialogUtil for T {
    pub fn message_box(&self, msg: &str, title: &str) {
        do as_utf16_p(msg) |msg_p| {
            do as_utf16_p(title) |title_p| {
                unsafe {
                    user32::MessageBoxW(self.hwnd(), msg_p, title_p, 0u32);
                }
            }
        }
    }
}
<|endoftext|>


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

//! The Rust parser and macro expander.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/")]

#![feature(core)]
#![feature(rustc_private)]

extern crate arena;
extern crate fmt_macros;
extern crate serialize;
extern crate term;
extern crate libc;
#[macro_use] extern crate log;
#[macro_use] #[no_link] extern crate bitflags as rustc_bitflags;

extern crate serialize as rustc_serialize; // used by deriving
extern crate unicode_xid;

// A variant of 'try!' that panics on Err(FatalError). This is used as a
// crutch on the way towards a non-panic!-prone parser. It should be used
// for fatal parsing errors; eventually we plan to convert all code using
// panictry to just use normal try
macro_rules! panictry {
    ($e:expr) => ({
        use std::result::Result::{Ok, Err};
        use diagnostic::FatalError;
        match $e {
            Ok(e) => e,
            Err(FatalError) => panic!(FatalError)
        }
    })
}

pub mod util {
    pub mod interner;
    #[cfg(test)]
    pub mod parser_testing;
    pub mod small_vector;
}

pub mod diagnostics {
    pub mod macros;
    pub mod plugin;
    pub mod registry;
}

pub mod syntax {
    pub use ext;
    pub use parse;
    pub use ast;
}

pub mod abi;
pub mod ast;
pub mod ast_util;
pub mod attr;
pub mod codemap;
pub mod config;
pub mod diagnostic;
pub mod feature_gate;
pub mod fold;
pub mod owned_slice;
pub mod parse;
pub mod ptr;
pub mod show_span;
pub mod std_inject;
pub mod str;
pub mod test;
pub mod visit;

pub mod print {
    pub mod pp;
    pub mod pprust;
}

pub mod ext {
    pub mod asm;
    pub mod base;
    pub mod build;
    pub mod cfg;
    pub mod concat;
    pub mod concat_idents;
    pub mod deriving;
    pub mod env;
    pub mod expand;
    pub mod format;
    pub mod log_syntax;
    pub mod mtwt;
    pub mod quote;
    pub mod source_util;
    pub mod trace_macros;

    pub mod tt {
        pub mod transcribe;
        pub mod macro_parser;
        pub mod macro_rules;
    }
}
<commit_msg>Remove #![feature(core)]<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Rust parser and macro expander.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/")]

#![feature(rustc_private)]

extern crate arena;
extern crate fmt_macros;
extern crate serialize;
extern crate term;
extern crate libc;
#[macro_use] extern crate log;
#[macro_use] #[no_link] extern crate bitflags as rustc_bitflags;

extern crate serialize as rustc_serialize; // used by deriving
extern crate unicode_xid;

// A variant of 'try!' that panics on Err(FatalError). This is used as a
// crutch on the way towards a non-panic!-prone parser. It should be used
// for fatal parsing errors; eventually we plan to convert all code using
// panictry to just use normal try
macro_rules! panictry {
    ($e:expr) => ({
        use std::result::Result::{Ok, Err};
        use diagnostic::FatalError;
        match $e {
            Ok(e) => e,
            Err(FatalError) => panic!(FatalError)
        }
    })
}

pub mod util {
    pub mod interner;
    #[cfg(test)]
    pub mod parser_testing;
    pub mod small_vector;
}

pub mod diagnostics {
    pub mod macros;
    pub mod plugin;
    pub mod registry;
}

pub mod syntax {
    pub use ext;
    pub use parse;
    pub use ast;
}

pub mod abi;
pub mod ast;
pub mod ast_util;
pub mod attr;
pub mod codemap;
pub mod config;
pub mod diagnostic;
pub mod feature_gate;
pub mod fold;
pub mod owned_slice;
pub mod parse;
pub mod ptr;
pub mod show_span;
pub mod std_inject;
pub mod str;
pub mod test;
pub mod visit;

pub mod print {
    pub mod pp;
    pub mod pprust;
}

pub mod ext {
    pub mod asm;
    pub mod base;
    pub mod build;
    pub mod cfg;
    pub mod concat;
    pub mod concat_idents;
    pub mod deriving;
    pub mod env;
    pub mod expand;
    pub mod format;
    pub mod log_syntax;
    pub mod mtwt;
    pub mod quote;
    pub mod source_util;
    pub mod trace_macros;

    pub mod tt {
        pub mod transcribe;
        pub mod macro_parser;
        pub mod macro_rules;
    }
}
<|endoftext|>