<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 dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeListBinding;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::js::{JS, MutNullableJS, Root, RootedReference};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::node::{ChildrenMutation, Node};
use dom::window::Window;
use dom_struct::dom_struct;
use std::cell::Cell;

#[derive(JSTraceable, HeapSizeOf)]
#[must_root]
pub enum NodeListType {
    Simple(Vec<JS<Node>>),
    Children(ChildrenList),
}

// https://dom.spec.whatwg.org/#interface-nodelist
#[dom_struct]
pub struct NodeList {
    reflector_: Reflector,
    list_type: NodeListType,
}

impl NodeList {
    #[allow(unrooted_must_root)]
    pub fn new_inherited(list_type: NodeListType) -> NodeList {
        NodeList {
            reflector_: Reflector::new(),
            list_type: list_type,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(window: &Window, list_type: NodeListType) -> Root<NodeList> {
        reflect_dom_object(box NodeList::new_inherited(list_type),
                           window,
                           NodeListBinding::Wrap)
    }

    pub fn new_simple_list<T>(window: &Window, iter: T) -> Root<NodeList>
                              where T: Iterator<Item=Root<Node>> {
        NodeList::new(window, NodeListType::Simple(iter.map(|r| JS::from_ref(&*r)).collect()))
    }

    pub fn new_simple_list_slice(window: &Window, slice: &[&Node]) -> Root<NodeList> {
        NodeList::new(window, NodeListType::Simple(slice.iter().map(|r| JS::from_ref(*r)).collect()))
    }

    pub fn new_child_list(window: &Window, node: &Node) -> Root<NodeList> {
        NodeList::new(window, NodeListType::Children(ChildrenList::new(node)))
    }

    pub fn empty(window: &Window) -> Root<NodeList> {
        NodeList::new(window, NodeListType::Simple(vec![]))
    }
}

impl NodeListMethods for NodeList {
    // https://dom.spec.whatwg.org/#dom-nodelist-length
    fn Length(&self) -> u32 {
        match self.list_type {
            NodeListType::Simple(ref elems) => elems.len() as u32,
            NodeListType::Children(ref list) => list.len(),
        }
    }

    // https://dom.spec.whatwg.org/#dom-nodelist-item
    fn Item(&self, index: u32) -> Option<Root<Node>> {
        match self.list_type {
            NodeListType::Simple(ref elems) => {
                elems.get(index as usize).map(|node| Root::from_ref(&**node))
            },
            NodeListType::Children(ref list) => list.item(index),
        }
    }

    // https://dom.spec.whatwg.org/#dom-nodelist-item
    fn IndexedGetter(&self, index: u32) -> Option<Root<Node>> {
        self.Item(index)
    }
}

impl NodeList {
    pub fn as_children_list(&self) -> &ChildrenList {
        if let NodeListType::Children(ref list) = self.list_type {
            list
        } else {
            panic!("called as_children_list() on a simple node list")
        }
    }

    pub fn as_simple_list(&self) -> &Vec<JS<Node>> {
        if let NodeListType::Simple(ref list) = self.list_type {
            list
        } else {
            panic!("called as_simple_list() on a children node list")
        }
    }

    pub fn iter(&self) -> NodeListIterator {
        NodeListIterator {
            nodes: self,
            offset: 0,
        }
    }
}

#[derive(JSTraceable, HeapSizeOf)]
#[must_root]
pub struct ChildrenList {
    node: JS<Node>,
    #[ignore_heap_size_of = "Defined in rust-mozjs"]
    last_visited: MutNullableJS<Node>,
    last_index: Cell<u32>,
}

impl ChildrenList {
    pub fn new(node: &Node) -> ChildrenList {
        let last_visited = node.GetFirstChild();
        ChildrenList {
            node: JS::from_ref(node),
            last_visited: MutNullableJS::new(last_visited.r()),
            last_index: Cell::new(0u32),
        }
    }

    pub fn len(&self) -> u32 {
        self.node.children_count()
    }

    pub fn item(&self, index: u32) -> Option<Root<Node>> {
        // This always start traversing the children from the closest element
        // among parent's first and last children and the last visited one.
        let len = self.len() as u32;
        if index >= len {
            return None;
        }
        if index == 0u32 {
            // Item is first child if any, not worth updating last visited.
            return self.node.GetFirstChild();
        }
        let last_index = self.last_index.get();
        if index == last_index {
            // Item is last visited child, no need to update last visited.
            return Some(self.last_visited.get().unwrap());
        }
        let last_visited = if index - 1u32 == last_index {
            // Item is last visited's next sibling.
            self.last_visited.get().unwrap().GetNextSibling().unwrap()
        } else if last_index > 0 && index == last_index - 1u32 {
            // Item is last visited's previous sibling.
            self.last_visited.get().unwrap().GetPreviousSibling().unwrap()
        } else if index > last_index {
            if index == len - 1u32 {
                // Item is parent's last child, not worth updating last visited.
                return Some(self.node.GetLastChild().unwrap());
            }
            if index <= last_index + (len - last_index) / 2u32 {
                // Item is closer to the last visited child and follows it.
                self.last_visited.get().unwrap()
                                 .inclusively_following_siblings()
                                 .nth((index - last_index) as usize).unwrap()
            } else {
                // Item is closer to parent's last child and obviously
                // precedes it.
                self.node.GetLastChild().unwrap()
                    .inclusively_preceding_siblings()
                    .nth((len - index - 1u32) as usize).unwrap()
            }
        } else if index >= last_index / 2u32 {
            // Item is closer to the last visited child and precedes it.
            self.last_visited.get().unwrap()
                             .inclusively_preceding_siblings()
                             .nth((last_index - index) as usize).unwrap()
        } else {
            // Item is closer to parent's first child and obviously follows it.
            debug_assert!(index < last_index / 2u32);
            self.node.GetFirstChild().unwrap()
                     .inclusively_following_siblings()
                     .nth(index as usize)
                     .unwrap()
        };
        self.last_visited.set(Some(&last_visited));
        self.last_index.set(index);
        Some(last_visited)
    }

    pub fn children_changed(&self, mutation: &ChildrenMutation) {
        fn prepend(list: &ChildrenList, added: &[&Node], next: &Node) {
            let len = added.len() as u32;
            if len == 0u32 {
                return;
            }
            let index = list.last_index.get();
            if index < len {
                list.last_visited.set(Some(added[index as usize]));
            } else if index / 2u32 >= len {
                // If last index is twice as large as the number of added nodes,
                // updating only it means that less nodes will be traversed if
                // caller is traversing the node list linearly.
                list.last_index.set(len + index);
            } else {
                // If last index is not twice as large but still larger,
                // it's better to update it to the number of added nodes.
                list.last_visited.set(Some(next));
                list.last_index.set(len);
            }
        }

        fn replace(list: &ChildrenList,
                   prev: Option<&Node>,
                   removed: &Node,
                   added: &[&Node],
                   next: Option<&Node>) {
            let index = list.last_index.get();
            if removed == &*list.last_visited.get().unwrap() {
                let visited = match (prev, added, next) {
                    (None, _, None) => {
                        // Such cases where parent had only one child should
                        // have been changed into ChildrenMutation::ReplaceAll
                        // by ChildrenMutation::replace().
                        unreachable!()
                    },
                    (_, added, _) if !added.is_empty() => added[0],
                    (_, _, Some(next)) => next,
                    (Some(prev), _, None) => {
                        list.last_index.set(index - 1u32);
                        prev
                    },
                };
                list.last_visited.set(Some(visited));
            } else if added.len() != 1 {
                // The replaced child isn't the last visited one, and there are
                // 0 or more than 1 nodes to replace it. Special care must be
                // given to update the state of that ChildrenList.
                match (prev, next) {
                    (Some(_), None) => {},
                    (None, Some(next)) => {
                        list.last_index.set(index - 1);
                        prepend(list, added, next);
                    },
                    (Some(_), Some(_)) => {
                        list.reset();
                    },
                    (None, None) => unreachable!(),
                }
            }
        }

        match *mutation {
            ChildrenMutation::Append { .. } => {},
            ChildrenMutation::Insert { .. } => {
                self.reset();
            },
            ChildrenMutation::Prepend { added, next } => {
                prepend(self, added, next);
            },
            ChildrenMutation::Replace { prev, removed, added, next } => {
                replace(self, prev, removed, added, next);
            },
            ChildrenMutation::ReplaceAll { added, .. } => {
                let len = added.len();
                let index = self.last_index.get();
                if len == 0 {
                    self.last_visited.set(None);
                    self.last_index.set(0u32);
                } else if index < len as u32 {
                    self.last_visited.set(Some(added[index as usize]));
                } else {
                    // Setting last visited to parent's last child serves no purpose,
                    // so the middle is arbitrarily chosen here in case the caller
                    // wants random access.
                    let middle = len / 2;
                    self.last_visited.set(Some(added[middle]));
                    self.last_index.set(middle as u32);
                }
            },
        }
    }

    fn reset(&self) {
        self.last_visited.set(self.node.GetFirstChild().r());
        self.last_index.set(0u32);
    }
}

pub struct NodeListIterator<'a> {
    nodes: &'a NodeList,
    offset: u32,
}

impl<'a> Iterator for NodeListIterator<'a> {
    type Item = Root<Node>;

    fn next(&mut self) -> Option<Root<Node>> {
        let result = self.nodes.Item(self.offset);
        self.offset = self.offset + 1;
        result
    }
}
<commit_msg>Auto merge of #17488 - frewsxcv:frewsxcv-return-node-list, r=jdm<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 dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeListBinding;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::js::{JS, MutNullableJS, Root, RootedReference};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::node::{ChildrenMutation, Node};
use dom::window::Window;
use dom_struct::dom_struct;
use std::cell::Cell;

#[derive(JSTraceable, HeapSizeOf)]
#[must_root]
pub enum NodeListType {
    Simple(Vec<JS<Node>>),
    Children(ChildrenList),
}

// https://dom.spec.whatwg.org/#interface-nodelist
#[dom_struct]
pub struct NodeList {
    reflector_: Reflector,
    list_type: NodeListType,
}

impl NodeList {
    #[allow(unrooted_must_root)]
    pub fn new_inherited(list_type: NodeListType) -> NodeList {
        NodeList {
            reflector_: Reflector::new(),
            list_type: list_type,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(window: &Window, list_type: NodeListType) -> Root<NodeList> {
        reflect_dom_object(box NodeList::new_inherited(list_type),
                           window,
                           NodeListBinding::Wrap)
    }

    pub fn new_simple_list<T>(window: &Window, iter: T) -> Root<NodeList>
                              where T: Iterator<Item=Root<Node>> {
        NodeList::new(window, NodeListType::Simple(iter.map(|r| JS::from_ref(&*r)).collect()))
    }

    pub fn new_simple_list_slice(window: &Window, slice: &[&Node]) -> Root<NodeList> {
        NodeList::new(window, NodeListType::Simple(slice.iter().map(|r| JS::from_ref(*r)).collect()))
    }

    pub fn new_child_list(window: &Window, node: &Node) -> Root<NodeList> {
        NodeList::new(window, NodeListType::Children(ChildrenList::new(node)))
    }

    pub fn empty(window: &Window) -> Root<NodeList> {
        NodeList::new(window, NodeListType::Simple(vec![]))
    }
}

impl NodeListMethods for NodeList {
    // https://dom.spec.whatwg.org/#dom-nodelist-length
    fn Length(&self) -> u32 {
        match self.list_type {
            NodeListType::Simple(ref elems) => elems.len() as u32,
            NodeListType::Children(ref list) => list.len(),
        }
    }

    // https://dom.spec.whatwg.org/#dom-nodelist-item
    fn Item(&self, index: u32) -> Option<Root<Node>> {
        match self.list_type {
            NodeListType::Simple(ref elems) => {
                elems.get(index as usize).map(|node| Root::from_ref(&**node))
            },
            NodeListType::Children(ref list) => list.item(index),
        }
    }

    // https://dom.spec.whatwg.org/#dom-nodelist-item
    fn IndexedGetter(&self, index: u32) -> Option<Root<Node>> {
        self.Item(index)
    }
}

impl NodeList {
    pub fn as_children_list(&self) -> &ChildrenList {
        if let NodeListType::Children(ref list) = self.list_type {
            list
        } else {
            panic!("called as_children_list() on a simple node list")
        }
    }

    pub fn as_simple_list(&self) -> &Vec<JS<Node>> {
        if let NodeListType::Simple(ref list) = self.list_type {
            list
        } else {
            panic!("called as_simple_list() on a children node list")
        }
    }

    pub fn iter<'a>(&'a self) -> impl Iterator<Item=Root<Node>> + 'a {
        let len = self.Length();
        (0..len).flat_map(move |i| self.Item(i))
    }
}

#[derive(JSTraceable, HeapSizeOf)]
#[must_root]
pub struct ChildrenList {
    node: JS<Node>,
    #[ignore_heap_size_of = "Defined in rust-mozjs"]
    last_visited: MutNullableJS<Node>,
    last_index: Cell<u32>,
}

impl ChildrenList {
    pub fn new(node: &Node) -> ChildrenList {
        let last_visited = node.GetFirstChild();
        ChildrenList {
            node: JS::from_ref(node),
            last_visited: MutNullableJS::new(last_visited.r()),
            last_index: Cell::new(0u32),
        }
    }

    pub fn len(&self) -> u32 {
        self.node.children_count()
    }

    pub fn item(&self, index: u32) -> Option<Root<Node>> {
        // This always start traversing the children from the closest element
        // among parent's first and last children and the last visited one.
        let len = self.len() as u32;
        if index >= len {
            return None;
        }
        if index == 0u32 {
            // Item is first child if any, not worth updating last visited.
            return self.node.GetFirstChild();
        }
        let last_index = self.last_index.get();
        if index == last_index {
            // Item is last visited child, no need to update last visited.
            return Some(self.last_visited.get().unwrap());
        }
        let last_visited = if index - 1u32 == last_index {
            // Item is last visited's next sibling.
            self.last_visited.get().unwrap().GetNextSibling().unwrap()
        } else if last_index > 0 && index == last_index - 1u32 {
            // Item is last visited's previous sibling.
            self.last_visited.get().unwrap().GetPreviousSibling().unwrap()
        } else if index > last_index {
            if index == len - 1u32 {
                // Item is parent's last child, not worth updating last visited.
                return Some(self.node.GetLastChild().unwrap());
            }
            if index <= last_index + (len - last_index) / 2u32 {
                // Item is closer to the last visited child and follows it.
                self.last_visited.get().unwrap()
                                 .inclusively_following_siblings()
                                 .nth((index - last_index) as usize).unwrap()
            } else {
                // Item is closer to parent's last child and obviously
                // precedes it.
                self.node.GetLastChild().unwrap()
                    .inclusively_preceding_siblings()
                    .nth((len - index - 1u32) as usize).unwrap()
            }
        } else if index >= last_index / 2u32 {
            // Item is closer to the last visited child and precedes it.
            self.last_visited.get().unwrap()
                             .inclusively_preceding_siblings()
                             .nth((last_index - index) as usize).unwrap()
        } else {
            // Item is closer to parent's first child and obviously follows it.
            debug_assert!(index < last_index / 2u32);
            self.node.GetFirstChild().unwrap()
                     .inclusively_following_siblings()
                     .nth(index as usize)
                     .unwrap()
        };
        self.last_visited.set(Some(&last_visited));
        self.last_index.set(index);
        Some(last_visited)
    }

    pub fn children_changed(&self, mutation: &ChildrenMutation) {
        fn prepend(list: &ChildrenList, added: &[&Node], next: &Node) {
            let len = added.len() as u32;
            if len == 0u32 {
                return;
            }
            let index = list.last_index.get();
            if index < len {
                list.last_visited.set(Some(added[index as usize]));
            } else if index / 2u32 >= len {
                // If last index is twice as large as the number of added nodes,
                // updating only it means that less nodes will be traversed if
                // caller is traversing the node list linearly.
                list.last_index.set(len + index);
            } else {
                // If last index is not twice as large but still larger,
                // it's better to update it to the number of added nodes.
                list.last_visited.set(Some(next));
                list.last_index.set(len);
            }
        }

        fn replace(list: &ChildrenList,
                   prev: Option<&Node>,
                   removed: &Node,
                   added: &[&Node],
                   next: Option<&Node>) {
            let index = list.last_index.get();
            if removed == &*list.last_visited.get().unwrap() {
                let visited = match (prev, added, next) {
                    (None, _, None) => {
                        // Such cases where parent had only one child should
                        // have been changed into ChildrenMutation::ReplaceAll
                        // by ChildrenMutation::replace().
                        unreachable!()
                    },
                    (_, added, _) if !added.is_empty() => added[0],
                    (_, _, Some(next)) => next,
                    (Some(prev), _, None) => {
                        list.last_index.set(index - 1u32);
                        prev
                    },
                };
                list.last_visited.set(Some(visited));
            } else if added.len() != 1 {
                // The replaced child isn't the last visited one, and there are
                // 0 or more than 1 nodes to replace it. Special care must be
                // given to update the state of that ChildrenList.
                match (prev, next) {
                    (Some(_), None) => {},
                    (None, Some(next)) => {
                        list.last_index.set(index - 1);
                        prepend(list, added, next);
                    },
                    (Some(_), Some(_)) => {
                        list.reset();
                    },
                    (None, None) => unreachable!(),
                }
            }
        }

        match *mutation {
            ChildrenMutation::Append { .. } => {},
            ChildrenMutation::Insert { .. } => {
                self.reset();
            },
            ChildrenMutation::Prepend { added, next } => {
                prepend(self, added, next);
            },
            ChildrenMutation::Replace { prev, removed, added, next } => {
                replace(self, prev, removed, added, next);
            },
            ChildrenMutation::ReplaceAll { added, .. } => {
                let len = added.len();
                let index = self.last_index.get();
                if len == 0 {
                    self.last_visited.set(None);
                    self.last_index.set(0u32);
                } else if index < len as u32 {
                    self.last_visited.set(Some(added[index as usize]));
                } else {
                    // Setting last visited to parent's last child serves no purpose,
                    // so the middle is arbitrarily chosen here in case the caller
                    // wants random access.
                    let middle = len / 2;
                    self.last_visited.set(Some(added[middle]));
                    self.last_index.set(middle as u32);
                }
            },
        }
    }

    fn reset(&self) {
        self.last_visited.set(self.node.GetFirstChild().r());
        self.last_index.set(0u32);
    }
}
<|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 cg;
use darling::util::Override;
use quote::{ToTokens, Tokens};
use syn::{self, Data, GenericParam, Path, WhereClause};
use synstructure::{BindingInfo, Structure, VariantInfo};

pub fn derive(mut input: syn::DeriveInput) -> Tokens {
    let mut where_clause = input.generics.where_clause.take();
    for param in &input.generics.params {
        let param = match *param {
            GenericParam::Type(ref param) => param,
            _ => continue,
        };
        cg::add_predicate(
            &mut where_clause,
            parse_quote!(#param: ::style_traits::ToCss),
        );
    }

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    if let Data::Enum(_) = input.data {
        assert!(input_attrs.function.is_none(), "#[css(function)] is not allowed on enums");
        assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums");
    }

    let match_body = {
        let s = Structure::new(&input);
        s.each_variant(|variant| {
            derive_variant_arm(variant, &mut where_clause)
        })
    };
    input.generics.where_clause = where_clause;

    let name = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let mut impls = quote! {
        impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut ::style_traits::CssWriter<W>,
            ) -> ::std::fmt::Result
            where
                W: ::std::fmt::Write,
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    ::style_traits::ToCss::to_css(
                        self,
                        &mut ::style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(
    variant: &VariantInfo,
    generics: &mut Option<WhereClause>,
) -> Tokens {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        quote! {
            ::std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        derive_variant_fields_expr(bindings, generics, separator)
    } else {
        quote! {
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name);
        identifier.push_str("(");
        expr = quote! {
            ::std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            ::std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

fn derive_variant_fields_expr(
    bindings: &[BindingInfo],
    where_clause: &mut Option<WhereClause>,
    separator: &str,
) -> Tokens {
    let mut iter = bindings.iter().filter_map(|binding| {
        let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
        if attrs.skip {
            return None;
        }
        Some((binding, attrs))
    }).peekable();

    let (first, attrs) = match iter.next() {
        Some(pair) => pair,
        None => return quote! { Ok(()) },
    };
    if !attrs.iterable && iter.peek().is_none() {
        if attrs.field_bound {
            let ty = &first.ast().ty;
            cg::add_predicate(where_clause, parse_quote!(#ty: ::style_traits::ToCss));
        }
        let mut expr = quote! { ::style_traits::ToCss::to_css(#first, dest) };
        if let Some(condition) = attrs.skip_if {
            expr = quote! {
                if !#condition(#first) {
                    #expr
                }
            }
        }
        return expr;
    }

    let mut expr = derive_single_field_expr(first, attrs, where_clause);
    for (binding, attrs) in iter {
        derive_single_field_expr(binding, attrs, where_clause).to_tokens(&mut expr)
    }

    quote! {{
        let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator);
        #expr
        Ok(())
    }}
}

fn derive_single_field_expr(
    field: &BindingInfo,
    attrs: CssFieldAttrs,
    where_clause: &mut Option<WhereClause>,
) -> Tokens {
    let mut expr = if attrs.iterable {
        if let Some(if_empty) = attrs.if_empty {
            return quote! {
                {
                    let mut iter = #field.iter().peekable();
                    if iter.peek().is_none() {
                        writer.item(&::style_traits::values::Verbatim(#if_empty))?;
                    } else {
                        for item in iter {
                            writer.item(&item)?;
                        }
                    }
                }
            };
        }
        quote! {
            for item in #field.iter() {
                writer.item(&item)?;
            }
        }
    } else {
        if attrs.field_bound {
            let ty = &field.ast().ty;
            cg::add_predicate(where_clause, parse_quote!(#ty: ::style_traits::ToCss));
        }
        quote! { writer.item(#field)?; }
    };

    if let Some(condition) = attrs.skip_if {
        expr = quote! {
            if !#condition(#field) {
                #expr
            }
        }
    }

    expr
}

#[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)]
struct CssInputAttrs {
    derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    comma: bool,
}

#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
pub struct CssVariantAttrs {
    pub function: Option<Override<String>>,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub aliases: Option<String>,
}

#[darling(attributes(css), default)]
#[derive(Default, FromField)]
struct CssFieldAttrs {
    if_empty: Option<String>,
    field_bound: bool,
    iterable: bool,
    skip: bool,
    skip_if: Option<Path>,
}
<commit_msg>Simplify some code in #[derive(ToCss)]<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 cg;
use darling::util::Override;
use quote::{ToTokens, Tokens};
use syn::{self, Data, Path, WhereClause};
use synstructure::{BindingInfo, Structure, VariantInfo};

pub fn derive(mut input: syn::DeriveInput) -> Tokens {
    let mut where_clause = input.generics.where_clause.take();
    for param in input.generics.type_params() {
        cg::add_predicate(
            &mut where_clause,
            parse_quote!(#param: ::style_traits::ToCss),
        );
    }

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    if let Data::Enum(_) = input.data {
        assert!(input_attrs.function.is_none(), "#[css(function)] is not allowed on enums");
        assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums");
    }

    let match_body = {
        let s = Structure::new(&input);
        s.each_variant(|variant| {
            derive_variant_arm(variant, &mut where_clause)
        })
    };
    input.generics.where_clause = where_clause;

    let name = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let mut impls = quote! {
        impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut ::style_traits::CssWriter<W>,
            ) -> ::std::fmt::Result
            where
                W: ::std::fmt::Write,
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    ::style_traits::ToCss::to_css(
                        self,
                        &mut ::style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(
    variant: &VariantInfo,
    generics: &mut Option<WhereClause>,
) -> Tokens {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        quote! {
            ::std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        derive_variant_fields_expr(bindings, generics, separator)
    } else {
        quote! {
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name);
        identifier.push_str("(");
        expr = quote! {
            ::std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            ::std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

fn derive_variant_fields_expr(
    bindings: &[BindingInfo],
    where_clause: &mut Option<WhereClause>,
    separator: &str,
) -> Tokens {
    let mut iter = bindings.iter().filter_map(|binding| {
        let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
        if attrs.skip {
            return None;
        }
        Some((binding, attrs))
    }).peekable();

    let (first, attrs) = match iter.next() {
        Some(pair) => pair,
        None => return quote! { Ok(()) },
    };
    if !attrs.iterable && iter.peek().is_none() {
        if attrs.field_bound {
            let ty = &first.ast().ty;
            cg::add_predicate(where_clause, parse_quote!(#ty: ::style_traits::ToCss));
        }
        let mut expr = quote! { ::style_traits::ToCss::to_css(#first, dest) };
        if let Some(condition) = attrs.skip_if {
            expr = quote! {
                if !#condition(#first) {
                    #expr
                }
            }
        }
        return expr;
    }

    let mut expr = derive_single_field_expr(first, attrs, where_clause);
    for (binding, attrs) in iter {
        derive_single_field_expr(binding, attrs, where_clause).to_tokens(&mut expr)
    }

    quote! {{
        let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator);
        #expr
        Ok(())
    }}
}

fn derive_single_field_expr(
    field: &BindingInfo,
    attrs: CssFieldAttrs,
    where_clause: &mut Option<WhereClause>,
) -> Tokens {
    let mut expr = if attrs.iterable {
        if let Some(if_empty) = attrs.if_empty {
            return quote! {
                {
                    let mut iter = #field.iter().peekable();
                    if iter.peek().is_none() {
                        writer.item(&::style_traits::values::Verbatim(#if_empty))?;
                    } else {
                        for item in iter {
                            writer.item(&item)?;
                        }
                    }
                }
            };
        }
        quote! {
            for item in #field.iter() {
                writer.item(&item)?;
            }
        }
    } else {
        if attrs.field_bound {
            let ty = &field.ast().ty;
            cg::add_predicate(where_clause, parse_quote!(#ty: ::style_traits::ToCss));
        }
        quote! { writer.item(#field)?; }
    };

    if let Some(condition) = attrs.skip_if {
        expr = quote! {
            if !#condition(#field) {
                #expr
            }
        }
    }

    expr
}

#[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)]
struct CssInputAttrs {
    derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    comma: bool,
}

#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
pub struct CssVariantAttrs {
    pub function: Option<Override<String>>,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub aliases: Option<String>,
}

#[darling(attributes(css), default)]
#[derive(Default, FromField)]
struct CssFieldAttrs {
    if_empty: Option<String>,
    field_bound: bool,
    iterable: bool,
    skip: bool,
    skip_if: Option<Path>,
}
<|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.

pub mod census;
pub mod service;
pub mod signals;
pub mod service_updater;

use std::net::SocketAddr;
use std::thread;
use std::sync::{Arc, RwLock};
use std::time::Duration;

use butterfly;
use butterfly::member::Member;
use butterfly::trace::Trace;
use butterfly::rumor::service::Service as ServiceRumor;
use butterfly::server::timing::Timing;
use hcore::crypto::{default_cache_key_path, SymKey};
use time::{SteadyTime, Duration as TimeDuration};

use self::service_updater::ServiceUpdater;
use error::{Error, Result};
use config::{gconfig, UpdateStrategy, Topology};
use manager::service::Service;
use manager::census::{CensusUpdate, CensusList, CensusEntry};
use manager::signals::SignalEvent;
use package::Package;
use http_gateway;
use util;

static LOGKEY: &'static str = "MR";

#[derive(Clone)]
pub struct State {
    pub butterfly: butterfly::Server,
    pub census_list: Arc<RwLock<CensusList>>,
    pub services: Arc<RwLock<Vec<Service>>>,
}

impl State {
    pub fn new(butterfly: butterfly::Server) -> Self {
        State {
            butterfly: butterfly,
            census_list: Arc::new(RwLock::new(CensusList::new())),
            services: Arc::new(RwLock::new(Vec::new())),
        }
    }
}

pub struct Manager {
    state: State,
    updater: ServiceUpdater,
}

impl Manager {
    pub fn new() -> Result<Manager> {
        let mut member = Member::new();
        member.set_persistent(gconfig().gossip_permanent());
        member.set_swim_port(gconfig().gossip_listen().port() as i32);
        member.set_gossip_port(gconfig().gossip_listen().port() as i32);

        let ring_key = match gconfig().ring() {
            &Some(ref ring_with_revision) => {
                outputln!("Joining ring {}", ring_with_revision);
                Some(try!(SymKey::get_pair_for(&ring_with_revision, &default_cache_key_path(None))))
            }
            &None => None,
        };

        let server = try!(butterfly::Server::new(gconfig().gossip_listen(),
                                                 gconfig().gossip_listen(),
                                                 member,
                                                 Trace::default(),
                                                 ring_key,
                                                 None));
        outputln!("Butterfly Member ID {}", server.member_id());
        for peer_addr in gconfig().gossip_peer() {
            let addr: SocketAddr = peer_addr.parse().unwrap();
            let mut peer = Member::new();
            peer.set_address(format!("{}", addr.ip()));
            peer.set_swim_port(addr.port() as i32);
            peer.set_gossip_port(addr.port() as i32);
            server.member_list.add_initial_member(peer);
        }
        Ok(Manager {
            updater: ServiceUpdater::new(server.clone()),
            state: State::new(server),
        })
    }

    pub fn add_service(&mut self,
                       package: Package,
                       topology: Topology,
                       update_strategy: UpdateStrategy)
                       -> Result<()> {
        let service = try!(Service::new(package.clone(),
                                        gconfig().group(),
                                        gconfig().organization().clone(),
                                        topology,
                                        update_strategy));
        let hostname = try!(util::sys::hostname());
        let ip = try!(util::sys::ip());
        // TODO: We should do this much earlier, to confirm that the ports we expose are not
        //       bullshit.
        let mut exposes = Vec::new();
        for port in package.exposes().into_iter() {
            let port_num = try!(port.parse::<u32>().map_err(|e| sup_error!(Error::InvalidPort(e))));
            exposes.push(port_num);
        }
        let service_rumor = ServiceRumor::new(self.state.butterfly.member_id(),
                                              package.ident(),
                                              service.service_group.group.clone(),
                                              service.service_group.organization.clone(),
                                              hostname,
                                              ip.to_string(),
                                              exposes);
        self.state.butterfly.insert_service(service_rumor);

        if topology == Topology::Leader || topology == Topology::Initializer {
            // Note - eventually, we need to deal with suitability here. The original implementation
            // didn't have this working either.
            self.state.butterfly.start_election(service.service_group.clone(), 0, 0);
        }

        self.updater.add(&service);
        self.state.services.write().expect("Services lock is poisoned!").push(service);
        Ok(())
    }

    pub fn build_census(&mut self, last_update: &CensusUpdate) -> Result<(bool, CensusUpdate)> {
        let update = CensusUpdate::new(self.state.butterfly.service_store.get_update_counter(),
                                       self.state.butterfly.election_store.get_update_counter(),
                                       self.state.butterfly.update_store.get_update_counter(),
                                       self.state.butterfly.member_list.get_update_counter());

        if &update != last_update {
            let mut cl = CensusList::new();
            debug!("Updating census from butterfly data");
            self.state.butterfly.service_store.with_keys(|(_service_group, rumors)| {
                for (_member_id, service) in rumors.iter() {
                    let mut ce = CensusEntry::default();
                    ce.populate_from_service(service);
                    cl.insert(String::from(self.state.butterfly.member_id()), ce);
                }
            });
            self.state.butterfly.election_store.with_keys(|(_service_group, rumors)| {
                // We know you have an election, and this is the only key in the hash
                let election = rumors.get("election").unwrap();
                cl.populate_from_election(election);
            });
            self.state.butterfly.update_store.with_keys(|(_service_group, rumors)| {
                // We know you have an election, and this is the only key in the hash
                let election = rumors.get("election").unwrap();
                cl.populate_from_update_election(election);
            });
            self.state.butterfly.member_list.with_members(|member| {
                cl.populate_from_member(member);
                if let Some(health) = self.state.butterfly.member_list.health_of(member) {
                    cl.populate_from_health(member, health);
                }
            });
            *self.state.census_list.write().expect("Census list lock is poisoned!") = cl;
            return Ok((true, update));
        }
        Ok((false, update))
    }

    fn check_for_incoming_signals(&mut self) -> bool {
        match signals::check_for_signal() {
            Some(SignalEvent::Shutdown) => {
                for service in self.state
                    .services
                    .write()
                    .expect("Services lock is poisoned!")
                    .iter_mut() {
                    outputln!("Shutting down {}", service);
                    service.down()
                        .unwrap_or_else(|err| outputln!("Failed to shutdown {}: {}", service, err));
                }
                true
            }
            Some(SignalEvent::Passthrough(signal_code)) => {
                for service in self.state
                    .services
                    .read()
                    .expect("Services lock is poisoned!")
                    .iter() {
                    outputln!("Forwarding signal {} to {}", signal_code, service);
                    if let Err(e) = service.send_signal(signal_code) {
                        outputln!("Failed to send signal {} to {}: {}",
                                  signal_code,
                                  service,
                                  e);
                    }
                }
                false
            }
            None => false,
        }
    }

    /// Walk each service and check if it has an updated package installed via the Update Strategy.
    pub fn check_for_updated_packages(&mut self) {
        let member_id = {
            self.state.butterfly.member_id().to_string()
        };
        let census_list = self.state.census_list.read().expect("Census list lock is poisoned!");
        for service in self.state.services.write().expect("Services lock is poisoned!").iter_mut() {
            if self.updater.check_for_updated_package(service, &census_list) {
                let mut rumor = {
                    let list = self.state
                        .butterfly
                        .service_store
                        .list
                        .read()
                        .expect("Rumor store lock poisoned");
                    list.get(&service.service_group.as_string())
                        .and_then(|r| r.get(&member_id))
                        .unwrap()
                        .clone()
                };
                let incarnation = rumor.get_incarnation() + 1;
                rumor.set_package_ident(service.package.to_string());
                rumor.set_incarnation(incarnation);
                self.state.butterfly.insert_service(rumor);
            }
        }
    }

    //  * Start butterfly
    //  Loop {
    //    * Check for incoming signals; forward them; shut down if necessary
    //    * Check if each service needs its package updated
    //      * Update the package
    //    * Check if the Census needs building from Butterfly, or the package changed
    //      * Loop the services, and reconfigure the service from the Census
    //    * Reap any dead children
    //    * Start or restart the services
    //  }
    //
    pub fn run(&mut self) -> Result<()> {
        // Set the global signal handlers
        signals::init();

        outputln!("Starting butterfly on {}",
                  gconfig().gossip_listen().to_string());
        try!(self.state.butterfly.start(Timing::default()));
        debug!("butterfly server started");
        outputln!("Starting http-gateway on {}", gconfig().http_listen_addr());
        try!(http_gateway::Server::new(self.state.clone()).start());
        debug!("http-gateway server started");

        // Watch for updates
        let mut last_census_update = CensusUpdate::new(0, 0, 0, 0);

        'services: loop {
            let next_check = SteadyTime::now() + TimeDuration::milliseconds(1000);
            // Check for incoming signals.
            //
            // This takes signals passed to `hab-sup` and either shuts down all the services, or
            // passes the signals through. This functionality is totally going to need a refactor
            // when we get all the way to a single-sup-per-kernel model, since passing all random
            // signals through to all services is most certainly not what you want.
            //
            // This function returns true if we are supposed to shut the system down, false if we
            // can keep going.
            if self.check_for_incoming_signals() {
                outputln!("Habitat thanks you - shutting down!");
                return Ok(());
            }

            // Check for updated packages; this updates the Service to point to the new service
            // struct, and then marks it for restarting.
            self.check_for_updated_packages();

            // Check if any elections need restarting.
            self.state.butterfly.restart_elections();

            // Try and build the census from the gossip data, updating the last_census_update with
            // the resulting checkpoints. The census is our representation of the data produced
            // by Butterfly.
            let (census_updated, ncu) = try!(self.build_census(&last_census_update));
            if census_updated {
                last_census_update = ncu;
            }

            for service in self.state
                .services
                .write()
                .expect("Services lock is poisoned!")
                .iter_mut() {

                // Write out any files we received via butterfly
                let mut service_files_updated = false;
                for (incarnation, filename, body) in
                    self.state
                        .butterfly
                        .service_files_for(&service.service_group_str(),
                                           &service.current_service_files)
                        .into_iter() {
                    let result = service.write_butterfly_service_file(filename, incarnation, body);
                    if service_files_updated == false && result == true {
                        service_files_updated = true;
                    }
                }
                if service_files_updated {
                    service.file_updated();
                }

                // Write out any service configuration we received via butterfly
                let mut service_config_updated = false;
                if let Some((incarnation, config)) =
                    self.state
                        .butterfly
                        .service_config_for(&service.service_group_str(),
                                            service.service_config_incarnation) {
                    service_config_updated = service.write_butterfly_service_config(config);
                    service.service_config_incarnation = Some(incarnation);
                }

                // Reconfigure if necessary
                if census_updated || service_config_updated {
                    service.reconfigure(&self.state
                        .census_list
                        .read()
                        .expect("Census list lock is poisoned!"));
                }

                // If this service has not been initialized, do so now.
                service.initialize();

                // Reap dead children
                let _ = service.check_process();

                // Start or restart the service
                if service.initialized && (service.needs_restart || service.is_down()) {
                    match service.restart(&self.state
                        .census_list
                        .read()
                        .expect("Census list lock is poisoned!")) {
                        Ok(()) => {}
                        Err(e) => outputln!("Cannot restart service: {}", e),
                    }
                }
            }

            let time_to_wait = (next_check - SteadyTime::now()).num_milliseconds();
            if time_to_wait > 0 {
                thread::sleep(Duration::from_millis(time_to_wait as u64));
            }
        }
    }
}
<commit_msg>Resolve peer address before assigning it's IP to member<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.

pub mod census;
pub mod service;
pub mod signals;
pub mod service_updater;

use std::net::{SocketAddr, ToSocketAddrs};
use std::thread;
use std::sync::{Arc, RwLock};
use std::time::Duration;

use butterfly;
use butterfly::member::Member;
use butterfly::trace::Trace;
use butterfly::rumor::service::Service as ServiceRumor;
use butterfly::server::timing::Timing;
use hcore::crypto::{default_cache_key_path, SymKey};
use time::{SteadyTime, Duration as TimeDuration};

use self::service_updater::ServiceUpdater;
use error::{Error, Result};
use config::{gconfig, UpdateStrategy, Topology};
use manager::service::Service;
use manager::census::{CensusUpdate, CensusList, CensusEntry};
use manager::signals::SignalEvent;
use package::Package;
use http_gateway;
use util;

static LOGKEY: &'static str = "MR";

#[derive(Clone)]
pub struct State {
    pub butterfly: butterfly::Server,
    pub census_list: Arc<RwLock<CensusList>>,
    pub services: Arc<RwLock<Vec<Service>>>,
}

impl State {
    pub fn new(butterfly: butterfly::Server) -> Self {
        State {
            butterfly: butterfly,
            census_list: Arc::new(RwLock::new(CensusList::new())),
            services: Arc::new(RwLock::new(Vec::new())),
        }
    }
}

pub struct Manager {
    state: State,
    updater: ServiceUpdater,
}

impl Manager {
    pub fn new() -> Result<Manager> {
        let mut member = Member::new();
        member.set_persistent(gconfig().gossip_permanent());
        member.set_swim_port(gconfig().gossip_listen().port() as i32);
        member.set_gossip_port(gconfig().gossip_listen().port() as i32);

        let ring_key = match gconfig().ring() {
            &Some(ref ring_with_revision) => {
                outputln!("Joining ring {}", ring_with_revision);
                Some(try!(SymKey::get_pair_for(&ring_with_revision, &default_cache_key_path(None))))
            }
            &None => None,
        };

        let server = try!(butterfly::Server::new(gconfig().gossip_listen(),
                                                 gconfig().gossip_listen(),
                                                 member,
                                                 Trace::default(),
                                                 ring_key,
                                                 None));
        outputln!("Butterfly Member ID {}", server.member_id());
        for peer_addr in gconfig().gossip_peer() {
            let addrs: Vec<SocketAddr> = peer_addr.to_socket_addrs()
                                                  .expect("Unable to resolve domain")
                                                  .collect();
            let addr: SocketAddr = addrs[0];
            let mut peer = Member::new();
            peer.set_address(format!("{}", addr.ip()));
            peer.set_swim_port(addr.port() as i32);
            peer.set_gossip_port(addr.port() as i32);
            server.member_list.add_initial_member(peer);
        }
        Ok(Manager {
            updater: ServiceUpdater::new(server.clone()),
            state: State::new(server),
        })
    }

    pub fn add_service(&mut self,
                       package: Package,
                       topology: Topology,
                       update_strategy: UpdateStrategy)
                       -> Result<()> {
        let service = try!(Service::new(package.clone(),
                                        gconfig().group(),
                                        gconfig().organization().clone(),
                                        topology,
                                        update_strategy));
        let hostname = try!(util::sys::hostname());
        let ip = try!(util::sys::ip());
        // TODO: We should do this much earlier, to confirm that the ports we expose are not
        //       bullshit.
        let mut exposes = Vec::new();
        for port in package.exposes().into_iter() {
            let port_num = try!(port.parse::<u32>().map_err(|e| sup_error!(Error::InvalidPort(e))));
            exposes.push(port_num);
        }
        let service_rumor = ServiceRumor::new(self.state.butterfly.member_id(),
                                              package.ident(),
                                              service.service_group.group.clone(),
                                              service.service_group.organization.clone(),
                                              hostname,
                                              ip.to_string(),
                                              exposes);
        self.state.butterfly.insert_service(service_rumor);

        if topology == Topology::Leader || topology == Topology::Initializer {
            // Note - eventually, we need to deal with suitability here. The original implementation
            // didn't have this working either.
            self.state.butterfly.start_election(service.service_group.clone(), 0, 0);
        }

        self.updater.add(&service);
        self.state.services.write().expect("Services lock is poisoned!").push(service);
        Ok(())
    }

    pub fn build_census(&mut self, last_update: &CensusUpdate) -> Result<(bool, CensusUpdate)> {
        let update = CensusUpdate::new(self.state.butterfly.service_store.get_update_counter(),
                                       self.state.butterfly.election_store.get_update_counter(),
                                       self.state.butterfly.update_store.get_update_counter(),
                                       self.state.butterfly.member_list.get_update_counter());

        if &update != last_update {
            let mut cl = CensusList::new();
            debug!("Updating census from butterfly data");
            self.state.butterfly.service_store.with_keys(|(_service_group, rumors)| {
                for (_member_id, service) in rumors.iter() {
                    let mut ce = CensusEntry::default();
                    ce.populate_from_service(service);
                    cl.insert(String::from(self.state.butterfly.member_id()), ce);
                }
            });
            self.state.butterfly.election_store.with_keys(|(_service_group, rumors)| {
                // We know you have an election, and this is the only key in the hash
                let election = rumors.get("election").unwrap();
                cl.populate_from_election(election);
            });
            self.state.butterfly.update_store.with_keys(|(_service_group, rumors)| {
                // We know you have an election, and this is the only key in the hash
                let election = rumors.get("election").unwrap();
                cl.populate_from_update_election(election);
            });
            self.state.butterfly.member_list.with_members(|member| {
                cl.populate_from_member(member);
                if let Some(health) = self.state.butterfly.member_list.health_of(member) {
                    cl.populate_from_health(member, health);
                }
            });
            *self.state.census_list.write().expect("Census list lock is poisoned!") = cl;
            return Ok((true, update));
        }
        Ok((false, update))
    }

    fn check_for_incoming_signals(&mut self) -> bool {
        match signals::check_for_signal() {
            Some(SignalEvent::Shutdown) => {
                for service in self.state
                    .services
                    .write()
                    .expect("Services lock is poisoned!")
                    .iter_mut() {
                    outputln!("Shutting down {}", service);
                    service.down()
                        .unwrap_or_else(|err| outputln!("Failed to shutdown {}: {}", service, err));
                }
                true
            }
            Some(SignalEvent::Passthrough(signal_code)) => {
                for service in self.state
                    .services
                    .read()
                    .expect("Services lock is poisoned!")
                    .iter() {
                    outputln!("Forwarding signal {} to {}", signal_code, service);
                    if let Err(e) = service.send_signal(signal_code) {
                        outputln!("Failed to send signal {} to {}: {}",
                                  signal_code,
                                  service,
                                  e);
                    }
                }
                false
            }
            None => false,
        }
    }

    /// Walk each service and check if it has an updated package installed via the Update Strategy.
    pub fn check_for_updated_packages(&mut self) {
        let member_id = {
            self.state.butterfly.member_id().to_string()
        };
        let census_list = self.state.census_list.read().expect("Census list lock is poisoned!");
        for service in self.state.services.write().expect("Services lock is poisoned!").iter_mut() {
            if self.updater.check_for_updated_package(service, &census_list) {
                let mut rumor = {
                    let list = self.state
                        .butterfly
                        .service_store
                        .list
                        .read()
                        .expect("Rumor store lock poisoned");
                    list.get(&service.service_group.as_string())
                        .and_then(|r| r.get(&member_id))
                        .unwrap()
                        .clone()
                };
                let incarnation = rumor.get_incarnation() + 1;
                rumor.set_package_ident(service.package.to_string());
                rumor.set_incarnation(incarnation);
                self.state.butterfly.insert_service(rumor);
            }
        }
    }

    //  * Start butterfly
    //  Loop {
    //    * Check for incoming signals; forward them; shut down if necessary
    //    * Check if each service needs its package updated
    //      * Update the package
    //    * Check if the Census needs building from Butterfly, or the package changed
    //      * Loop the services, and reconfigure the service from the Census
    //    * Reap any dead children
    //    * Start or restart the services
    //  }
    //
    pub fn run(&mut self) -> Result<()> {
        // Set the global signal handlers
        signals::init();

        outputln!("Starting butterfly on {}",
                  gconfig().gossip_listen().to_string());
        try!(self.state.butterfly.start(Timing::default()));
        debug!("butterfly server started");
        outputln!("Starting http-gateway on {}", gconfig().http_listen_addr());
        try!(http_gateway::Server::new(self.state.clone()).start());
        debug!("http-gateway server started");

        // Watch for updates
        let mut last_census_update = CensusUpdate::new(0, 0, 0, 0);

        'services: loop {
            let next_check = SteadyTime::now() + TimeDuration::milliseconds(1000);
            // Check for incoming signals.
            //
            // This takes signals passed to `hab-sup` and either shuts down all the services, or
            // passes the signals through. This functionality is totally going to need a refactor
            // when we get all the way to a single-sup-per-kernel model, since passing all random
            // signals through to all services is most certainly not what you want.
            //
            // This function returns true if we are supposed to shut the system down, false if we
            // can keep going.
            if self.check_for_incoming_signals() {
                outputln!("Habitat thanks you - shutting down!");
                return Ok(());
            }

            // Check for updated packages; this updates the Service to point to the new service
            // struct, and then marks it for restarting.
            self.check_for_updated_packages();

            // Check if any elections need restarting.
            self.state.butterfly.restart_elections();

            // Try and build the census from the gossip data, updating the last_census_update with
            // the resulting checkpoints. The census is our representation of the data produced
            // by Butterfly.
            let (census_updated, ncu) = try!(self.build_census(&last_census_update));
            if census_updated {
                last_census_update = ncu;
            }

            for service in self.state
                .services
                .write()
                .expect("Services lock is poisoned!")
                .iter_mut() {

                // Write out any files we received via butterfly
                let mut service_files_updated = false;
                for (incarnation, filename, body) in
                    self.state
                        .butterfly
                        .service_files_for(&service.service_group_str(),
                                           &service.current_service_files)
                        .into_iter() {
                    let result = service.write_butterfly_service_file(filename, incarnation, body);
                    if service_files_updated == false && result == true {
                        service_files_updated = true;
                    }
                }
                if service_files_updated {
                    service.file_updated();
                }

                // Write out any service configuration we received via butterfly
                let mut service_config_updated = false;
                if let Some((incarnation, config)) =
                    self.state
                        .butterfly
                        .service_config_for(&service.service_group_str(),
                                            service.service_config_incarnation) {
                    service_config_updated = service.write_butterfly_service_config(config);
                    service.service_config_incarnation = Some(incarnation);
                }

                // Reconfigure if necessary
                if census_updated || service_config_updated {
                    service.reconfigure(&self.state
                        .census_list
                        .read()
                        .expect("Census list lock is poisoned!"));
                }

                // If this service has not been initialized, do so now.
                service.initialize();

                // Reap dead children
                let _ = service.check_process();

                // Start or restart the service
                if service.initialized && (service.needs_restart || service.is_down()) {
                    match service.restart(&self.state
                        .census_list
                        .read()
                        .expect("Census list lock is poisoned!")) {
                        Ok(()) => {}
                        Err(e) => outputln!("Cannot restart service: {}", e),
                    }
                }
            }

            let time_to_wait = (next_check - SteadyTime::now()).num_milliseconds();
            if time_to_wait > 0 {
                thread::sleep(Duration::from_millis(time_to_wait as u64));
            }
        }
    }
}
<|endoftext|>


<commit_before>//!
//! Values manipulated by endpoints
//!

use std::time::Duration;

extern crate chrono;
use self::chrono::{DateTime, Local};

extern crate serde_json;

///
/// The type of values manipulated by endpoints.
///
#[derive(Debug, Clone)]
pub enum Type {
    ///
    /// # Trivial values
    ///

    /// An empty value. Used for instance to inform that a countdown
    /// has reached 0 or that a device is ready.
    Unit,

    /// A boolean. Used for instance for on-off switches, presence
    /// detectors, etc.
    Bool,

    ///
    /// # Time
    ///

    /// A duration. Used for instance in countdowns.
    Duration,

    /// A precise timestamp. Used for instance to determine when an
    /// event has taken place.
    TimeStamp,

    Temperature,

    ///
    /// ...
    ///
    Color,
    Json,
    Binary,
}

/// A temperature. Internal representation may be either Fahrenheit or
/// Celcius. The FoxBox adapters are expected to perform conversions
/// to the format requested by their devices.
#[derive(Debug, Clone)]
pub enum Temperature {
    /// Fahrenheit
    F(f64),
    /// Celcius
    C(f64),
}

impl Temperature {
    /// Get a temperature in Fahrenheit.
    pub fn as_f(&self) -> f64 {
        unimplemented!();
    }

    /// Get a temperature in Celcius.
    pub fn as_c(&self) -> f64 {
        unimplemented!();
    }
}

/// A color. Internal representation may vary. The FoxBox adapters are
/// expected to perform conversions to the format requested by their
/// device.
#[derive(Debug, Clone)]
pub enum Color {
    RGBA(f64, f64, f64, f64, f64)
}

/// An actual value that may be transmitted from/to a Service.
#[derive(Debug, Clone)]
pub enum Value {
    Unit,
    Bool(bool),
    Duration(Duration),
    TimeStamp(chrono::DateTime<Local>),
    Temperature(Temperature),
    Color(Color),

    // FIXME: Add more as we identify needs
    Json(serde_json::value::Value),
    Binary {data: Vec<u8>, mimetype: String}
}

impl Value {
    pub fn get_type(&self) -> Type {
        match *self {
            Value::Unit => Type::Unit,
            Value::Bool(_) => Type::Bool,
            Value::Duration(_) => Type::Duration,
            Value::TimeStamp(_) => Type::TimeStamp,
            Value::Temperature(_) => Type::Temperature,
            Value::Color(_) => Type::Color,
            Value::Json(_) => Type::Json,
            Value::Binary{..} => Type::Binary,
        }
    }
}
<commit_msg>[fxbox/taxonomy] Implementing ordering on values<commit_after>//!
//! Values manipulated by endpoints
//!

use std::time::Duration;
use std::cmp::{PartialOrd, Ordering};

extern crate chrono;
use self::chrono::{DateTime, Local};

extern crate serde_json;

///
/// The type of values manipulated by endpoints.
///
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub enum Type {
    ///
    /// # Trivial values
    ///

    /// An empty value. Used for instance to inform that a countdown
    /// has reached 0 or that a device is ready.
    Unit,

    /// A boolean. Used for instance for on-off switches, presence
    /// detectors, etc.
    Bool,

    ///
    /// # Time
    ///

    /// A duration. Used for instance in countdowns.
    Duration,

    /// A precise timestamp. Used for instance to determine when an
    /// event has taken place.
    TimeStamp,

    Temperature,

    ///
    /// ...
    ///
    Color,
    Json,
    Binary,
}

/// A temperature. Internal representation may be either Fahrenheit or
/// Celcius. The FoxBox adapters are expected to perform conversions
/// to the format requested by their devices.
#[derive(Debug, Clone, PartialEq)]
pub enum Temperature {
    /// Fahrenheit
    F(f64),
    /// Celcius
    C(f64),
}

impl Temperature {
    /// Get a temperature in Fahrenheit.
    pub fn as_f(&self) -> f64 {
        unimplemented!();
    }

    /// Get a temperature in Celcius.
    pub fn as_c(&self) -> f64 {
        unimplemented!();
    }
}

impl PartialOrd for Temperature {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.as_c().partial_cmp(&other.as_c())
    }
}

/// A color. Internal representation may vary. The FoxBox adapters are
/// expected to perform conversions to the format requested by their
/// device.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Color {
    RGBA(f64, f64, f64, f64, f64)
}

/// Representation of an object in JSON. It is often (albeit not
/// always) possible to choose a more precise data structure for
/// representing values send/accepted by a service. If possible,
/// adapters should rather pick such more precise data structure.
#[derive(Debug, Clone, PartialEq)]
pub struct Json(serde_json::value::Value);

impl PartialOrd for Json {
    /// Two Json objects are never comparable to each other.
    fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
        None
    }
}

/// Base definitions for actual values. Most API clients will rather
/// use `Value`.
///
/// Splitting the defintion between `Value` and `ValueBase` is mostly
/// a convenience to refine the automatically-derived `PartialOrd` on
/// `ValueBase` into something that will never compare two values with
/// different types.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum ValueBase {
    Unit,
    Bool(bool),
    Duration(Duration),
    TimeStamp(chrono::DateTime<Local>),
    Temperature(Temperature),
    Color(Color),

    // FIXME: Add more as we identify needs
    Json(Json),
    Binary {data: Vec<u8>, mimetype: String}
}

impl ValueBase {
    pub fn get_type(&self) -> Type {
        match *self {
            ValueBase::Unit => Type::Unit,
            ValueBase::Bool(_) => Type::Bool,
            ValueBase::Duration(_) => Type::Duration,
            ValueBase::TimeStamp(_) => Type::TimeStamp,
            ValueBase::Temperature(_) => Type::Temperature,
            ValueBase::Color(_) => Type::Color,
            ValueBase::Json(_) => Type::Json,
            ValueBase::Binary{..} => Type::Binary,
        }
    }
}

/// Representation of an actual value that can be sent to/received
/// from a service.
#[derive(Debug, Clone, PartialEq)]
pub struct Value(ValueBase);

impl Value {
    /// Get the type attached to a value.
    pub fn get_type(&self) -> Type {
        self.0.get_type()
    }
}

impl PartialOrd for Value {
    /// Two values of the same type can be compared using the usual
    /// comparison for values of this type. Two values of distinct
    /// types cannot be compared.
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.get_type() != other.get_type() {
            None
        } else {
            self.0.partial_cmp(&other.0)
        }
    }
}
<|endoftext|>


<commit_before>//! A basic input + output stream example, copying the mic input stream to the default output stream

extern crate coreaudio;

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

use coreaudio::audio_unit::audio_format::LinearPcmFlags;
use coreaudio::audio_unit::render_callback::{self, data};
use coreaudio::audio_unit::{audio_unit_from_device_id, get_default_device_id, get_device_name};
use coreaudio::audio_unit::{Element, SampleFormat, Scope, StreamFormat};
use coreaudio::sys::*;

const SAMPLE_RATE: f64 = 44100.0;

type S = f32;
const SAMPLE_FORMAT: SampleFormat = SampleFormat::F32;
// type S = i32; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I32;
// type S = i16; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I16;
// type S = i8; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I8;

fn main() -> Result<(), coreaudio::Error> {
    let input_device_id = get_default_device_id(true).unwrap();
    let output_device_id = get_default_device_id(false).unwrap();
    println!(
        "Input device: {}",
        get_device_name(input_device_id).unwrap()
    );
    println!(
        "Output device: {}",
        get_device_name(output_device_id).unwrap()
    );
    let mut input_audio_unit = audio_unit_from_device_id(input_device_id, true)?;
    let mut output_audio_unit = audio_unit_from_device_id(output_device_id, false)?;

    let format_flag = match SAMPLE_FORMAT {
        SampleFormat::F32 => LinearPcmFlags::IS_FLOAT,
        SampleFormat::I32 | SampleFormat::I16 | SampleFormat::I8 => {
            LinearPcmFlags::IS_SIGNED_INTEGER
        }
    };

    let in_stream_format = StreamFormat {
        sample_rate: SAMPLE_RATE,
        sample_format: SAMPLE_FORMAT,
        flags: format_flag | LinearPcmFlags::IS_PACKED,
        channels: 2,
    };

    let out_stream_format = StreamFormat {
        sample_rate: SAMPLE_RATE,
        sample_format: SAMPLE_FORMAT,
        flags: format_flag | LinearPcmFlags::IS_PACKED,
        channels: 2,
    };

    println!("input={:#?}", &in_stream_format);
    println!("output={:#?}", &out_stream_format);
    println!("input_asbd={:#?}", &in_stream_format.to_asbd());
    println!("output_asbd={:#?}", &out_stream_format.to_asbd());

    let id = kAudioUnitProperty_StreamFormat;
    let asbd = in_stream_format.to_asbd();
    input_audio_unit.set_property(id, Scope::Output, Element::Input, Some(&asbd))?;

    let asbd = out_stream_format.to_asbd();
    output_audio_unit.set_property(id, Scope::Input, Element::Output, Some(&asbd))?;

    let buffer_left = Arc::new(Mutex::new(VecDeque::<S>::new()));
    let producer_left = buffer_left.clone();
    let consumer_left = buffer_left.clone();
    let buffer_right = Arc::new(Mutex::new(VecDeque::<S>::new()));
    let producer_right = buffer_right.clone();
    let consumer_right = buffer_right.clone();

    // seed roughly 1 second of data to create a delay in the feedback loop for easier testing
    for buffer in vec![buffer_left, buffer_right] {
        let mut buffer = buffer.lock().unwrap();
        for _ in 0..(out_stream_format.sample_rate as i32) {
            buffer.push_back(0 as S);
        }
    }

    type Args = render_callback::Args<data::Interleaved<S>>;

    input_audio_unit.set_input_callback(move |args| {
        let Args {
            num_frames, data, ..
        } = args;
        println!("input cb {} frames", num_frames);
        let buffer_left = producer_left.lock().unwrap();
        let buffer_right = producer_right.lock().unwrap();
        let mut buffers = vec![buffer_left, buffer_right];
        for i in 0..num_frames {
            for channel in 0..2 {
                let value: S = data.buffer[2 * i + channel];
                buffers[channel].push_back(value);
            }
        }
        Ok(())
    })?;
    input_audio_unit.start()?;

    output_audio_unit.set_render_callback(move |args: Args| {
        let Args {
            num_frames, data, ..
        } = args;
        println!("output cb {} frames", num_frames);
        let buffer_left = consumer_left.lock().unwrap();
        let buffer_right = consumer_right.lock().unwrap();
        let mut buffers = vec![buffer_left, buffer_right];
        for i in 0..num_frames {
            // Default other channels to copy value from first channel as a fallback
            let zero: S = 0 as S;
            let f: S = *buffers[0].front().unwrap_or(&zero);
            for channel in 0..2 {
                let sample: S = buffers[channel].pop_front().unwrap_or(f);
                data.buffer[2 * i + channel] = sample;
            }
        }
        Ok(())
    })?;
    output_audio_unit.start()?;

    std::thread::sleep(std::time::Duration::from_millis(100000));

    Ok(())
}
<commit_msg>Add rate listener to interleaved feedback example<commit_after>//! A basic input + output stream example, copying the mic input stream to the default output stream

extern crate coreaudio;

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

use coreaudio::audio_unit::audio_format::LinearPcmFlags;
use coreaudio::audio_unit::render_callback::{self, data};
use coreaudio::audio_unit::{audio_unit_from_device_id, get_default_device_id, get_device_name};
use coreaudio::audio_unit::{Element, SampleFormat, Scope, StreamFormat, RateListener};
use coreaudio::sys::*;

const SAMPLE_RATE: f64 = 44100.0;

type S = f32;
const SAMPLE_FORMAT: SampleFormat = SampleFormat::F32;
// type S = i32; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I32;
// type S = i16; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I16;
// type S = i8; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I8;

fn main() -> Result<(), coreaudio::Error> {
    let input_device_id = get_default_device_id(true).unwrap();
    let output_device_id = get_default_device_id(false).unwrap();
    println!(
        "Input device: {}",
        get_device_name(input_device_id).unwrap()
    );
    println!(
        "Output device: {}",
        get_device_name(output_device_id).unwrap()
    );
    let mut input_audio_unit = audio_unit_from_device_id(input_device_id, true)?;
    let mut output_audio_unit = audio_unit_from_device_id(output_device_id, false)?;

    let format_flag = match SAMPLE_FORMAT {
        SampleFormat::F32 => LinearPcmFlags::IS_FLOAT,
        SampleFormat::I32 | SampleFormat::I16 | SampleFormat::I8 => {
            LinearPcmFlags::IS_SIGNED_INTEGER
        }
    };

    let in_stream_format = StreamFormat {
        sample_rate: SAMPLE_RATE,
        sample_format: SAMPLE_FORMAT,
        flags: format_flag | LinearPcmFlags::IS_PACKED,
        channels: 2,
    };

    let out_stream_format = StreamFormat {
        sample_rate: SAMPLE_RATE,
        sample_format: SAMPLE_FORMAT,
        flags: format_flag | LinearPcmFlags::IS_PACKED,
        channels: 2,
    };

    println!("input={:#?}", &in_stream_format);
    println!("output={:#?}", &out_stream_format);
    println!("input_asbd={:#?}", &in_stream_format.to_asbd());
    println!("output_asbd={:#?}", &out_stream_format.to_asbd());

    let id = kAudioUnitProperty_StreamFormat;
    let asbd = in_stream_format.to_asbd();
    input_audio_unit.set_property(id, Scope::Output, Element::Input, Some(&asbd))?;

    let asbd = out_stream_format.to_asbd();
    output_audio_unit.set_property(id, Scope::Input, Element::Output, Some(&asbd))?;

    let buffer_left = Arc::new(Mutex::new(VecDeque::<S>::new()));
    let producer_left = buffer_left.clone();
    let consumer_left = buffer_left.clone();
    let buffer_right = Arc::new(Mutex::new(VecDeque::<S>::new()));
    let producer_right = buffer_right.clone();
    let consumer_right = buffer_right.clone();

    // Register a rate listener for playback
    let mut listener_pb = RateListener::new(output_device_id, None)?;
    listener_pb.register()?;

    // Register a rate listener for capture
    let mut listener_cap = RateListener::new(input_device_id, None)?;
    listener_cap.register()?;

    // seed roughly 1 second of data to create a delay in the feedback loop for easier testing
    for buffer in vec![buffer_left, buffer_right] {
        let mut buffer = buffer.lock().unwrap();
        for _ in 0..(out_stream_format.sample_rate as i32) {
            buffer.push_back(0 as S);
        }
    }

    type Args = render_callback::Args<data::Interleaved<S>>;

    input_audio_unit.set_input_callback(move |args| {
        let Args {
            num_frames, data, ..
        } = args;
        println!("input cb {} frames", num_frames);
        let buffer_left = producer_left.lock().unwrap();
        let buffer_right = producer_right.lock().unwrap();
        let mut buffers = vec![buffer_left, buffer_right];
        for i in 0..num_frames {
            for channel in 0..2 {
                let value: S = data.buffer[2 * i + channel];
                buffers[channel].push_back(value);
            }
        }
        Ok(())
    })?;
    input_audio_unit.start()?;

    output_audio_unit.set_render_callback(move |args: Args| {
        let Args {
            num_frames, data, ..
        } = args;
        println!("output cb {} frames", num_frames);
        let buffer_left = consumer_left.lock().unwrap();
        let buffer_right = consumer_right.lock().unwrap();
        let mut buffers = vec![buffer_left, buffer_right];
        for i in 0..num_frames {
            // Default other channels to copy value from first channel as a fallback
            let zero: S = 0 as S;
            let f: S = *buffers[0].front().unwrap_or(&zero);
            for channel in 0..2 {
                let sample: S = buffers[channel].pop_front().unwrap_or(f);
                data.buffer[2 * i + channel] = sample;
            }
        }
        Ok(())
    })?;
    output_audio_unit.start()?;
    for _ in 0..1000 {
        std::thread::sleep(std::time::Duration::from_millis(100));
        if listener_cap.get_nbr_values() > 0 {
            println!("capture rate change: {:?}", listener_cap.drain_values());
        }
        if listener_pb.get_nbr_values() > 0 {
            println!("playback rate change: {:?}", listener_pb.drain_values());
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before><commit_msg>Add doc comments of Database API<commit_after><|endoftext|>


<commit_before><commit_msg>testing for ruby twitter-commit bot<commit_after><|endoftext|>


<commit_before>use macros::hashmap;
use std::collections::HashMap;

#[test]
fn test_empty() {
    let expected: HashMap<u32, u32> = HashMap::new();
    let computed: HashMap<u32, u32> = hashmap!();
    assert_eq!(computed, expected);
}

#[test]
#[ignore]
fn test_single() {
    let mut expected = HashMap::new();
    expected.insert(1, "one");
    assert_eq!(hashmap!(1 => "one"), expected);
}

#[test]
#[ignore]
fn test_no_trailing_comma() {
    let mut expected = HashMap::new();
    expected.insert(1, "one");
    expected.insert(2, "two");
    assert_eq!(hashmap!(1 => "one", 2 => "two"), expected);
}

#[test]
#[ignore]
fn test_trailing_comma() {
    let mut expected = HashMap::new();
    expected.insert('h', 89);
    expected.insert('a', 1);
    expected.insert('s', 19);
    expected.insert('h', 8);
    assert_eq!(
        hashmap!(
            'h' => 89,
            'a' => 1,
            's' => 19,
            'h' => 8,
        ),
        expected
    );
}

#[test]
#[ignore]
fn test_nested() {
    let mut expected = HashMap::new();
    expected.insert("non-empty", {
        let mut subhashmap = HashMap::new();
        subhashmap.insert(23, 623);
        subhashmap.insert(34, 21);
        subhashmap
    });
    expected.insert("empty", HashMap::new());
    assert_eq!(
        hashmap!(
            "non-empty" => hashmap!(
                23 => 623,
                34 => 21
            ),
            "empty" => hashmap!()
        ),
        expected
    );
}

#[test]
#[ignore]
fn test_type_override() {
    // The macro should always use std::collections::HashMap and ignore crate::std::collections::HashMap
    mod std {
        pub mod collections {
            pub struct HashMap;

            impl HashMap {
                #[allow(dead_code)]
                pub fn new() -> Self {
                    panic!("Do not allow users to override which HashMap is used");
                }

                #[allow(dead_code)]
                pub fn insert<K, V>(&mut self, _key: K, _val: V) {
                    panic!("Do not allow users to override which HashMap is used");
                }
            }
        }
    }

    let _computed = hashmap!(1 => 2, 3 => 4);
}

#[test]
#[ignore]
fn test_compile_fails_comma_sep() {
    simple_trybuild::compile_fail("comma-sep.rs");
}

#[test]
#[ignore]
fn test_compile_fails_double_commas() {
    simple_trybuild::compile_fail("double-commas.rs");
}

#[test]
#[ignore]
fn test_compile_fails_only_comma() {
    simple_trybuild::compile_fail("only-comma.rs");
}

#[test]
#[ignore]
fn test_compile_fails_single_argument() {
    simple_trybuild::compile_fail("single-argument.rs");
}

#[test]
#[ignore]
fn test_compile_fails_triple_arguments() {
    simple_trybuild::compile_fail("triple-arguments.rs");
}

#[test]
#[ignore]
fn test_compile_fails_only_arrow() {
    simple_trybuild::compile_fail("only-arrow.rs");
}

#[test]
#[ignore]
fn test_compile_fails_two_arrows() {
    simple_trybuild::compile_fail("two-arrows.rs");
}

mod test {
    use macros::hashmap;
    #[test]
    #[ignore]
    fn type_not_in_scope() {
        let _expected: ::std::collections::HashMap<(), ()> = hashmap!();
    }
}

mod simple_trybuild {
    use std::path::PathBuf;
    use std::process::Command;

    pub fn compile_fail(file_name: &str) {
        let invalid_path: PathBuf = ["tests", "invalid"].iter().collect::<PathBuf>();

        let mut file_path = invalid_path.clone();
        file_path.push(file_name);
        assert!(
            file_path.exists(),
            "{:?} does not exist.",
            file_path.into_os_string()
        );

        let test_name = file_name.replace(".", "-");
        let macros_dir = ["..", "..", "target", "tests", "macros"]
            .iter()
            .collect::<PathBuf>();

        let result = Command::new("cargo")
            .current_dir(invalid_path)
            .arg("build")
            .arg("--offline")
            .arg("--target-dir")
            .arg(macros_dir)
            .arg("--bin")
            .arg(test_name)
            .output();

        if let Ok(result) = result {
            assert!(
                !result.status.success(),
                "Expected {:?} to fail to compile, but it succeeded.",
                file_path
            );
        } else {
            panic!("Running subprocess failed.");
        }
    }
}
<commit_msg>macros: additional tests without HashMap in scope (#942)<commit_after>use macros::hashmap;
use std::collections::HashMap;

#[test]
fn test_empty() {
    let expected: HashMap<u32, u32> = HashMap::new();
    let computed: HashMap<u32, u32> = hashmap!();
    assert_eq!(computed, expected);
}

#[test]
#[ignore]
fn test_single() {
    let mut expected = HashMap::new();
    expected.insert(1, "one");
    assert_eq!(hashmap!(1 => "one"), expected);
}

#[test]
#[ignore]
fn test_no_trailing_comma() {
    let mut expected = HashMap::new();
    expected.insert(1, "one");
    expected.insert(2, "two");
    assert_eq!(hashmap!(1 => "one", 2 => "two"), expected);
}

#[test]
#[ignore]
fn test_trailing_comma() {
    let mut expected = HashMap::new();
    expected.insert('h', 89);
    expected.insert('a', 1);
    expected.insert('s', 19);
    expected.insert('h', 8);
    assert_eq!(
        hashmap!(
            'h' => 89,
            'a' => 1,
            's' => 19,
            'h' => 8,
        ),
        expected
    );
}

#[test]
#[ignore]
fn test_nested() {
    let mut expected = HashMap::new();
    expected.insert("non-empty", {
        let mut subhashmap = HashMap::new();
        subhashmap.insert(23, 623);
        subhashmap.insert(34, 21);
        subhashmap
    });
    expected.insert("empty", HashMap::new());
    assert_eq!(
        hashmap!(
            "non-empty" => hashmap!(
                23 => 623,
                34 => 21
            ),
            "empty" => hashmap!()
        ),
        expected
    );
}

mod test {
    use macros::hashmap;
    #[test]
    #[ignore]
    fn type_not_in_scope() {
        let _empty: ::std::collections::HashMap<(), ()> = hashmap!();
        let _expected = hashmap!(23=> 623, 34 => 21);
    }
}

#[test]
#[ignore]
fn test_type_override() {
    // The macro should always use std::collections::HashMap and ignore crate::std::collections::HashMap
    mod std {
        pub mod collections {
            pub struct HashMap;

            impl HashMap {
                #[allow(dead_code)]
                pub fn new() -> Self {
                    panic!("Do not allow users to override which HashMap is used");
                }

                #[allow(dead_code)]
                pub fn insert<K, V>(&mut self, _key: K, _val: V) {
                    panic!("Do not allow users to override which HashMap is used");
                }
            }
        }
    }

    let _computed = hashmap!(1 => 2, 3 => 4);
}

#[test]
#[ignore]
fn test_compile_fails_comma_sep() {
    simple_trybuild::compile_fail("comma-sep.rs");
}

#[test]
#[ignore]
fn test_compile_fails_double_commas() {
    simple_trybuild::compile_fail("double-commas.rs");
}

#[test]
#[ignore]
fn test_compile_fails_only_comma() {
    simple_trybuild::compile_fail("only-comma.rs");
}

#[test]
#[ignore]
fn test_compile_fails_single_argument() {
    simple_trybuild::compile_fail("single-argument.rs");
}

#[test]
#[ignore]
fn test_compile_fails_triple_arguments() {
    simple_trybuild::compile_fail("triple-arguments.rs");
}

#[test]
#[ignore]
fn test_compile_fails_only_arrow() {
    simple_trybuild::compile_fail("only-arrow.rs");
}

#[test]
#[ignore]
fn test_compile_fails_two_arrows() {
    simple_trybuild::compile_fail("two-arrows.rs");
}

mod simple_trybuild {
    use std::path::PathBuf;
    use std::process::Command;

    pub fn compile_fail(file_name: &str) {
        let invalid_path: PathBuf = ["tests", "invalid"].iter().collect::<PathBuf>();

        let mut file_path = invalid_path.clone();
        file_path.push(file_name);
        assert!(
            file_path.exists(),
            "{:?} does not exist.",
            file_path.into_os_string()
        );

        let test_name = file_name.replace(".", "-");
        let macros_dir = ["..", "..", "target", "tests", "macros"]
            .iter()
            .collect::<PathBuf>();

        let result = Command::new("cargo")
            .current_dir(invalid_path)
            .arg("build")
            .arg("--offline")
            .arg("--target-dir")
            .arg(macros_dir)
            .arg("--bin")
            .arg(test_name)
            .output();

        if let Ok(result) = result {
            assert!(
                !result.status.success(),
                "Expected {:?} to fail to compile, but it succeeded.",
                file_path
            );
        } else {
            panic!("Running subprocess failed.");
        }
    }
}
<|endoftext|>