<commit_before>use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
use crate::fold::DocFolder;

use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_span::symbol::sym;

pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
    name: "collect-trait-impls",
    run: collect_trait_impls,
    description: "retrieves trait impls for items in the crate",
};

pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
    let mut synth = SyntheticImplCollector::new(cx);
    let mut krate = synth.fold_crate(krate);

    let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect();

    let crate_items = {
        let mut coll = ItemCollector::new();
        krate = coll.fold_crate(krate);
        coll.items
    };

    let mut new_items = Vec::new();

    for &cnum in cx.tcx.crates().iter() {
        for &did in cx.tcx.all_trait_implementations(cnum).iter() {
            inline::build_impl(cx, did, None, &mut new_items);
        }
    }

    // Also try to inline primitive impls from other crates.
    let lang_items = cx.tcx.lang_items();
    let primitive_impls = [
        lang_items.isize_impl(),
        lang_items.i8_impl(),
        lang_items.i16_impl(),
        lang_items.i32_impl(),
        lang_items.i64_impl(),
        lang_items.i128_impl(),
        lang_items.usize_impl(),
        lang_items.u8_impl(),
        lang_items.u16_impl(),
        lang_items.u32_impl(),
        lang_items.u64_impl(),
        lang_items.u128_impl(),
        lang_items.f32_impl(),
        lang_items.f64_impl(),
        lang_items.f32_runtime_impl(),
        lang_items.f64_runtime_impl(),
        lang_items.bool_impl(),
        lang_items.char_impl(),
        lang_items.str_impl(),
        lang_items.slice_impl(),
        lang_items.slice_u8_impl(),
        lang_items.str_alloc_impl(),
        lang_items.slice_alloc_impl(),
        lang_items.slice_u8_alloc_impl(),
        lang_items.const_ptr_impl(),
        lang_items.mut_ptr_impl(),
    ];

    for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
        if !def_id.is_local() {
            inline::build_impl(cx, def_id, None, &mut new_items);

            // FIXME(eddyb) is this `doc(hidden)` check needed?
            if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
                let self_ty = cx.tcx.type_of(def_id);
                let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id);
                let mut renderinfo = cx.renderinfo.borrow_mut();

                new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id)));
            }
        }
    }

    let mut cleaner = BadImplStripper { prims, items: crate_items };

    // scan through included items ahead of time to splice in Deref targets to the "valid" sets
    for it in &new_items {
        if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.inner {
            if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
                let target = items
                    .iter()
                    .filter_map(|item| match item.inner {
                        TypedefItem(ref t, true) => Some(&t.type_),
                        _ => None,
                    })
                    .next()
                    .expect("Deref impl without Target type");

                if let Some(prim) = target.primitive_type() {
                    cleaner.prims.insert(prim);
                } else if let Some(did) = target.def_id() {
                    cleaner.items.insert(did);
                }
            }
        }
    }

    new_items.retain(|it| {
        if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.inner {
            cleaner.keep_item(for_)
                || trait_.as_ref().map_or(false, |t| cleaner.keep_item(t))
                || blanket_impl.is_some()
        } else {
            true
        }
    });

    // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
    // doesn't work with it anyway, so pull them from the HIR map instead
    for &trait_did in cx.tcx.all_traits(LOCAL_CRATE).iter() {
        for &impl_node in cx.tcx.hir().trait_impls(trait_did) {
            let impl_did = cx.tcx.hir().local_def_id(impl_node);
            inline::build_impl(cx, impl_did, None, &mut new_items);
        }
    }

    if let Some(ref mut it) = krate.module {
        if let ModuleItem(Module { ref mut items, .. }) = it.inner {
            items.extend(synth.impls);
            items.extend(new_items);
        } else {
            panic!("collect-trait-impls can't run");
        }
    } else {
        panic!("collect-trait-impls can't run");
    }

    krate
}

struct SyntheticImplCollector<'a, 'tcx> {
    cx: &'a DocContext<'tcx>,
    impls: Vec<Item>,
}

impl<'a, 'tcx> SyntheticImplCollector<'a, 'tcx> {
    fn new(cx: &'a DocContext<'tcx>) -> Self {
        SyntheticImplCollector { cx, impls: Vec::new() }
    }
}

impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
    fn fold_item(&mut self, i: Item) -> Option<Item> {
        if i.is_struct() || i.is_enum() || i.is_union() {
            // FIXME(eddyb) is this `doc(hidden)` check needed?
            if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) {
                self.impls.extend(get_auto_trait_and_blanket_impls(
                    self.cx,
                    self.cx.tcx.type_of(i.def_id),
                    i.def_id,
                ));
            }
        }

        self.fold_item_recur(i)
    }
}

#[derive(Default)]
struct ItemCollector {
    items: FxHashSet<DefId>,
}

impl ItemCollector {
    fn new() -> Self {
        Self::default()
    }
}

impl DocFolder for ItemCollector {
    fn fold_item(&mut self, i: Item) -> Option<Item> {
        self.items.insert(i.def_id);

        self.fold_item_recur(i)
    }
}

struct BadImplStripper {
    prims: FxHashSet<PrimitiveType>,
    items: FxHashSet<DefId>,
}

impl BadImplStripper {
    fn keep_item(&self, ty: &Type) -> bool {
        if let Generic(_) = ty {
            // keep impls made on generics
            true
        } else if let Some(prim) = ty.primitive_type() {
            self.prims.contains(&prim)
        } else if let Some(did) = ty.def_id() {
            self.items.contains(&did)
        } else {
            false
        }
    }
}
<commit_msg>rustdoc: add "const_slice_ptr" and "mut_slice_ptr" trait impls<commit_after>use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
use crate::fold::DocFolder;

use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_span::symbol::sym;

pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
    name: "collect-trait-impls",
    run: collect_trait_impls,
    description: "retrieves trait impls for items in the crate",
};

pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
    let mut synth = SyntheticImplCollector::new(cx);
    let mut krate = synth.fold_crate(krate);

    let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect();

    let crate_items = {
        let mut coll = ItemCollector::new();
        krate = coll.fold_crate(krate);
        coll.items
    };

    let mut new_items = Vec::new();

    for &cnum in cx.tcx.crates().iter() {
        for &did in cx.tcx.all_trait_implementations(cnum).iter() {
            inline::build_impl(cx, did, None, &mut new_items);
        }
    }

    // Also try to inline primitive impls from other crates.
    let lang_items = cx.tcx.lang_items();
    let primitive_impls = [
        lang_items.isize_impl(),
        lang_items.i8_impl(),
        lang_items.i16_impl(),
        lang_items.i32_impl(),
        lang_items.i64_impl(),
        lang_items.i128_impl(),
        lang_items.usize_impl(),
        lang_items.u8_impl(),
        lang_items.u16_impl(),
        lang_items.u32_impl(),
        lang_items.u64_impl(),
        lang_items.u128_impl(),
        lang_items.f32_impl(),
        lang_items.f64_impl(),
        lang_items.f32_runtime_impl(),
        lang_items.f64_runtime_impl(),
        lang_items.bool_impl(),
        lang_items.char_impl(),
        lang_items.str_impl(),
        lang_items.slice_impl(),
        lang_items.slice_u8_impl(),
        lang_items.str_alloc_impl(),
        lang_items.slice_alloc_impl(),
        lang_items.slice_u8_alloc_impl(),
        lang_items.const_ptr_impl(),
        lang_items.mut_ptr_impl(),
        lang_items.const_slice_ptr_impl(),
        lang_items.mut_slice_ptr_impl(),
    ];

    for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
        if !def_id.is_local() {
            inline::build_impl(cx, def_id, None, &mut new_items);

            // FIXME(eddyb) is this `doc(hidden)` check needed?
            if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
                let self_ty = cx.tcx.type_of(def_id);
                let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id);
                let mut renderinfo = cx.renderinfo.borrow_mut();

                new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id)));
            }
        }
    }

    let mut cleaner = BadImplStripper { prims, items: crate_items };

    // scan through included items ahead of time to splice in Deref targets to the "valid" sets
    for it in &new_items {
        if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.inner {
            if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
                let target = items
                    .iter()
                    .filter_map(|item| match item.inner {
                        TypedefItem(ref t, true) => Some(&t.type_),
                        _ => None,
                    })
                    .next()
                    .expect("Deref impl without Target type");

                if let Some(prim) = target.primitive_type() {
                    cleaner.prims.insert(prim);
                } else if let Some(did) = target.def_id() {
                    cleaner.items.insert(did);
                }
            }
        }
    }

    new_items.retain(|it| {
        if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.inner {
            cleaner.keep_item(for_)
                || trait_.as_ref().map_or(false, |t| cleaner.keep_item(t))
                || blanket_impl.is_some()
        } else {
            true
        }
    });

    // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
    // doesn't work with it anyway, so pull them from the HIR map instead
    for &trait_did in cx.tcx.all_traits(LOCAL_CRATE).iter() {
        for &impl_node in cx.tcx.hir().trait_impls(trait_did) {
            let impl_did = cx.tcx.hir().local_def_id(impl_node);
            inline::build_impl(cx, impl_did, None, &mut new_items);
        }
    }

    if let Some(ref mut it) = krate.module {
        if let ModuleItem(Module { ref mut items, .. }) = it.inner {
            items.extend(synth.impls);
            items.extend(new_items);
        } else {
            panic!("collect-trait-impls can't run");
        }
    } else {
        panic!("collect-trait-impls can't run");
    }

    krate
}

struct SyntheticImplCollector<'a, 'tcx> {
    cx: &'a DocContext<'tcx>,
    impls: Vec<Item>,
}

impl<'a, 'tcx> SyntheticImplCollector<'a, 'tcx> {
    fn new(cx: &'a DocContext<'tcx>) -> Self {
        SyntheticImplCollector { cx, impls: Vec::new() }
    }
}

impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
    fn fold_item(&mut self, i: Item) -> Option<Item> {
        if i.is_struct() || i.is_enum() || i.is_union() {
            // FIXME(eddyb) is this `doc(hidden)` check needed?
            if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) {
                self.impls.extend(get_auto_trait_and_blanket_impls(
                    self.cx,
                    self.cx.tcx.type_of(i.def_id),
                    i.def_id,
                ));
            }
        }

        self.fold_item_recur(i)
    }
}

#[derive(Default)]
struct ItemCollector {
    items: FxHashSet<DefId>,
}

impl ItemCollector {
    fn new() -> Self {
        Self::default()
    }
}

impl DocFolder for ItemCollector {
    fn fold_item(&mut self, i: Item) -> Option<Item> {
        self.items.insert(i.def_id);

        self.fold_item_recur(i)
    }
}

struct BadImplStripper {
    prims: FxHashSet<PrimitiveType>,
    items: FxHashSet<DefId>,
}

impl BadImplStripper {
    fn keep_item(&self, ty: &Type) -> bool {
        if let Generic(_) = ty {
            // keep impls made on generics
            true
        } else if let Some(prim) = ty.primitive_type() {
            self.prims.contains(&prim)
        } else if let Some(did) = ty.def_id() {
            self.items.contains(&did)
        } else {
            false
        }
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

use std::cmp::Ordering;

use super::symbol_range::*;

///
/// A symbol map maps from one set of symbol ranges to another
///
pub struct SymbolMap<Symbol: PartialOrd+Clone> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: PartialOrd+Clone> SymbolMap<Symbol> {
    ///
    /// Creates a new symbol map
    ///
    pub fn new() -> SymbolMap<Symbol> {
        SymbolMap { ranges: vec![] }
    }

    ///
    /// Orders two symbols (makes unordered symbols equal)
    ///
    #[inline]
    fn order_symbols(a: &Symbol, b: &Symbol) -> Ordering {
        if let Some(order) = a.partial_cmp(b) {
            order
        } else {
            Ordering::Equal
        }
    }

    ///
    /// Orders two symbol ranges
    ///
    #[inline]
    fn order_ranges(a: &SymbolRange<Symbol>, b: &SymbolRange<Symbol>) -> Ordering {
        let ordering = SymbolMap::order_symbols(&a.lowest, &b.lowest);

        if ordering == Ordering::Equal {
            SymbolMap::order_symbols(&a.highest, &b.highest)
        } else {
            ordering
        }
    }

    ///
    /// Adds a range to those that are known about by this object
    ///
    pub fn add_range(&mut self, range: &SymbolRange<Symbol>) {
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Insert the range if it is not already in the map
        if let Err(insertion_pos) = existing {
            self.ranges.insert(insertion_pos, range.clone());
        }
    }

    ///
    /// Finds the ranges in this map that overlap the target ranges
    ///
    pub fn find_overlapping_ranges(&self, range: &SymbolRange<Symbol>) -> Vec<&SymbolRange<Symbol>> {
        let mut result = vec![];

        // Find the first range that matches (or the insertion position, which should be the first range wit a lowest value higher than the target range)
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Start returning values from here
        let mut pos = match existing {
            Ok(found_position) => found_position,
            Err(insert_position) => insert_position
        };

        // Move backwards if the previous position overlaps this one
        if pos > 0 && self.ranges[pos-1].highest >= range.lowest {
            pos -= 1;
        }

        // Apply the adjacency rule (if this range starts where the next range starts, then use the next range)
        if pos+1 < self.ranges.len() && self.ranges[pos].highest == self.ranges[pos+1].lowest && self.ranges[pos+1].lowest == range.lowest {
            pos += 1;
        }

        // TODO: can we construct a set of ranges such that one is missed here? Think maybe we can
        while pos < self.ranges.len() && self.ranges[pos].lowest <= range.highest {
            result.push(&self.ranges[pos]);
            pos += 1;
        }

        result
    }

    ///
    /// Creates a non-overlapping range from an overlapping one
    ///
    pub fn to_non_overlapping_map(&self) -> SymbolMap<Symbol> {
        // Create a vector of all the range symbols
        let mut range_symbols: Vec<Symbol> = self.ranges.iter()
            .map(|r| r.lowest.clone())
            .chain(self.ranges.iter().map(|r| r.highest.clone()))
            .collect();

        // Sort and dedupe (we'll get pairs of ranges)
        range_symbols.sort_by(SymbolMap::order_symbols);
        range_symbols.dedup();

        // Generate a new symbol map with these ranges
        // They'll overlap with the last value, which should be OK if following the rules for adjacent ranges in symbol_range.rs
        let mut result = vec![];
        for index in 0..range_symbols.len()-1 {
            result.push(SymbolRange::new(range_symbols[index].clone(), range_symbols[index+1].clone()));
        }

        // We already sorted everything, so bypass the usual 'add' method (which sorts as it goes)
        SymbolMap { ranges: result }
    }
}

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

    #[test]
    fn can_lookup_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(0, 1));
        let all    = map.find_overlapping_ranges(&SymbolRange::new(1, 3));
        let top    = map.find_overlapping_ranges(&SymbolRange::new(6, 6));

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(2, 5), &SymbolRange::new(3, 6)]);
        assert!(top == vec![&SymbolRange::new(3, 6)]);
    }

    #[test]
    fn can_lookup_mid_range() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(5, 10));
        map.add_range(&SymbolRange::new(11, 15));

        let mid = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(mid == vec![&SymbolRange::new(0, 4)]);
    }

    #[test]
    fn works_with_duplicate_lower_values() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 2));
        map.add_range(&SymbolRange::new(0, 3));

        let all    = map.find_overlapping_ranges(&SymbolRange::new(0, 1));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(0, 3)]);
    }

    #[test]
    fn obeys_adjacency_rule() {
        let mut map = SymbolMap::new();

        // By the adjacency rule for symbol ranges (in symbol_range.rs), '4' here is only in the upper range
        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(4, 8));

        let top = map.find_overlapping_ranges(&SymbolRange::new(4, 4));

        assert!(top == vec![&SymbolRange::new(4, 8)]);
    }

    #[test]
    fn can_get_non_overlapping_map() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(2, 3), &SymbolRange::new(3, 4), &SymbolRange::new(4, 5), &SymbolRange::new(5, 6)]);
    }
}
<commit_msg>Test the non-overlapping map with random single symbols in the map<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

use std::cmp::Ordering;

use super::symbol_range::*;

///
/// A symbol map maps from one set of symbol ranges to another
///
pub struct SymbolMap<Symbol: PartialOrd+Clone> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: PartialOrd+Clone> SymbolMap<Symbol> {
    ///
    /// Creates a new symbol map
    ///
    pub fn new() -> SymbolMap<Symbol> {
        SymbolMap { ranges: vec![] }
    }

    ///
    /// Orders two symbols (makes unordered symbols equal)
    ///
    #[inline]
    fn order_symbols(a: &Symbol, b: &Symbol) -> Ordering {
        if let Some(order) = a.partial_cmp(b) {
            order
        } else {
            Ordering::Equal
        }
    }

    ///
    /// Orders two symbol ranges
    ///
    #[inline]
    fn order_ranges(a: &SymbolRange<Symbol>, b: &SymbolRange<Symbol>) -> Ordering {
        let ordering = SymbolMap::order_symbols(&a.lowest, &b.lowest);

        if ordering == Ordering::Equal {
            SymbolMap::order_symbols(&a.highest, &b.highest)
        } else {
            ordering
        }
    }

    ///
    /// Adds a range to those that are known about by this object
    ///
    pub fn add_range(&mut self, range: &SymbolRange<Symbol>) {
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Insert the range if it is not already in the map
        if let Err(insertion_pos) = existing {
            self.ranges.insert(insertion_pos, range.clone());
        }
    }

    ///
    /// Finds the ranges in this map that overlap the target ranges
    ///
    pub fn find_overlapping_ranges(&self, range: &SymbolRange<Symbol>) -> Vec<&SymbolRange<Symbol>> {
        let mut result = vec![];

        // Find the first range that matches (or the insertion position, which should be the first range wit a lowest value higher than the target range)
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Start returning values from here
        let mut pos = match existing {
            Ok(found_position) => found_position,
            Err(insert_position) => insert_position
        };

        // Move backwards if the previous position overlaps this one
        if pos > 0 && self.ranges[pos-1].highest >= range.lowest {
            pos -= 1;
        }

        // Apply the adjacency rule (if this range starts where the next range starts, then use the next range)
        if pos+1 < self.ranges.len() && self.ranges[pos].highest == self.ranges[pos+1].lowest && self.ranges[pos+1].lowest == range.lowest {
            pos += 1;
        }

        // TODO: can we construct a set of ranges such that one is missed here? Think maybe we can
        while pos < self.ranges.len() && self.ranges[pos].lowest <= range.highest {
            result.push(&self.ranges[pos]);
            pos += 1;
        }

        result
    }

    ///
    /// Creates a non-overlapping range from an overlapping one
    ///
    pub fn to_non_overlapping_map(&self) -> SymbolMap<Symbol> {
        // Create a vector of all the range symbols
        let mut range_symbols: Vec<Symbol> = self.ranges.iter()
            .map(|r| r.lowest.clone())
            .chain(self.ranges.iter().map(|r| r.highest.clone()))
            .collect();

        // Sort and dedupe (we'll get pairs of ranges)
        range_symbols.sort_by(SymbolMap::order_symbols);
        range_symbols.dedup();

        // Generate a new symbol map with these ranges
        // They'll overlap with the last value, which should be OK if following the rules for adjacent ranges in symbol_range.rs
        let mut result = vec![];
        for index in 0..range_symbols.len()-1 {
            result.push(SymbolRange::new(range_symbols[index].clone(), range_symbols[index+1].clone()));
        }

        // We already sorted everything, so bypass the usual 'add' method (which sorts as it goes)
        SymbolMap { ranges: result }
    }
}

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

    #[test]
    fn can_lookup_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(0, 1));
        let all    = map.find_overlapping_ranges(&SymbolRange::new(1, 3));
        let top    = map.find_overlapping_ranges(&SymbolRange::new(6, 6));

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(2, 5), &SymbolRange::new(3, 6)]);
        assert!(top == vec![&SymbolRange::new(3, 6)]);
    }

    #[test]
    fn can_lookup_mid_range() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(5, 10));
        map.add_range(&SymbolRange::new(11, 15));

        let mid = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(mid == vec![&SymbolRange::new(0, 4)]);
    }

    #[test]
    fn works_with_duplicate_lower_values() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 2));
        map.add_range(&SymbolRange::new(0, 3));

        let all    = map.find_overlapping_ranges(&SymbolRange::new(0, 1));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(0, 3)]);
    }

    #[test]
    fn obeys_adjacency_rule() {
        let mut map = SymbolMap::new();

        // By the adjacency rule for symbol ranges (in symbol_range.rs), '4' here is only in the upper range
        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(4, 8));

        let top = map.find_overlapping_ranges(&SymbolRange::new(4, 4));

        assert!(top == vec![&SymbolRange::new(4, 8)]);
    }

    #[test]
    fn can_get_non_overlapping_map() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(2, 3), &SymbolRange::new(3, 4), &SymbolRange::new(4, 5), &SymbolRange::new(5, 6)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(2, 3), &SymbolRange::new(3, 5), &SymbolRange::new(5, 6)]);
    }
}
<|endoftext|>


<commit_before>use helpers;
use regex::RegexSet;
use slog::Logger;
use std::io::{Read, Write, BufWriter, BufReader};
use std::marker::Send;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::thread;
use structs::bound_file::{BoundFile, FileAction};
use structs::watcher::BindrsWatcher;
use time;

pub fn start<R: Read + Send + 'static, W: Write + Send + 'static>(
    log: &Logger,
    base_dir: &str,
    ignores: RegexSet,
    reader: R,
    writer: W,
) {
    let lock: Arc<Mutex<Vec<(String, i64, i32)>>> = Arc::new(Mutex::new(vec![]));
    let lock_clone = lock.clone();

    let base_dir_clone = base_dir.to_owned();
    let log_clone = log.clone();
    let child_1 = thread::spawn(move || {
        run_local_watcher(&log_clone, &base_dir_clone, &ignores, writer, lock_clone);
    });

    let base_dir_clone = base_dir.to_owned();
    let log_clone = log.clone();
    let child_2 = thread::spawn(move || {
        run_remote_listener(&log_clone, &base_dir_clone, reader, lock);
    });

    info!(log, "Ready!");

    let _ = child_1.join();
    let _ = child_2.join();
    info!(log, "BindRS Stopping");
}

fn run_local_watcher<W: Write>(
    log: &Logger,
    base_dir: &str,
    ingores: &RegexSet,
    writer: W,
    lock: Arc<Mutex<Vec<(String, i64, i32)>>>,
) {
    let mut writer = BufWriter::new(writer);
    let mut watcher = BindrsWatcher::new(base_dir, ingores);
    watcher.watch(log);
    let rx = watcher.rx.unwrap_or_else(|| {
        helpers::log_error_and_exit(log, "Couldn't get local receive channel off local watcher");
        panic!();
    });

    loop {
        let (a, p) = rx.recv().unwrap_or_else(|e| {
            helpers::log_error_and_exit(
                log,
                &format!("Failed to receive message from local watcher: {}", e),
            );
            panic!(e)
        });
        let full_str_path = format!("{}/{}", base_dir, p);
        let full_path = Path::new(&full_str_path);

        if a == FileAction::CreateUpdate && full_path.is_dir() {
            continue;
        }

        let p_clone = p.clone();

        {
            let mut recent_files = lock.lock().unwrap_or_else(|_| {
                helpers::log_error_and_exit(log, "Failed to aquire local fs lock, lock poisoned");
                panic!()
            });
            let (now_s, now_nano_s) = {
                let now_spec = time::now().to_timespec();
                (now_spec.sec, now_spec.nsec)
            };

            recent_files.retain(|&(_, ref time_s, ref time_nano_s)| {
                if now_s - time_s > 1 {
                    false
                } else if now_s - time_s == 1 {
                    now_nano_s - time_nano_s + 1000000000 /* 1e9 */ < 500000000 // 5e8
                } else {
                    now_nano_s - time_nano_s < 500000000 // 5e8
                }
            });

            if recent_files.iter().map(|&(ref path, _, _)| path).any(
                |&ref path| &p_clone == path,
            )
            {
                continue;
            }
        }

        let _guard = lock.lock().unwrap_or_else(|_| {
            helpers::log_error_and_exit(log, "Failed to aquire local fs lock, lock poisoned");
            panic!()
        });

        if a == FileAction::CreateUpdate && !full_path.exists() {
            debug!(log, "Skipping sending {} as file does not exist", p);
        } else {
            let bf = BoundFile::build_from_path_action(base_dir, p, a);
            debug!(log, "Sending {} to remote", bf.path);
            bf.to_writer(&mut writer);
        }
    }
}

fn run_remote_listener<R: Read>(
    log: &Logger,
    base_dir: &str,
    reader: R,
    lock: Arc<Mutex<Vec<(String, i64, i32)>>>,
) {
    let mut reader = BufReader::new(reader);
    loop {
        let bf = BoundFile::from_reader(&mut reader);
        let mut recent_files = lock.lock().unwrap_or_else(|_| {
            helpers::log_error_and_exit(log, "Failed to aquire local fs lock, lock poisoned");
            panic!()
        });
        debug!(log, "Receiving {} from remote", bf.path);
        bf.save_to_disk(base_dir);

        let (now_s, now_nano_s) = {
            let now_spec = time::now().to_timespec();
            (now_spec.sec, now_spec.nsec)
        };
        recent_files.push((bf.path, now_s, now_nano_s));
    }
}
<commit_msg>Add log lines per second if sendning/recieving files<commit_after>use helpers;
use regex::RegexSet;
use slog::Logger;
use std::io::{Read, Write, BufWriter, BufReader};
use std::marker::Send;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{self, TryRecvError, Receiver};
use std::thread::{self, sleep};
use std::time::Duration;
use structs::bound_file::{BoundFile, FileAction};
use structs::watcher::BindrsWatcher;
use time;

pub fn start<R: Read + Send + 'static, W: Write + Send + 'static>(
    log: &Logger,
    base_dir: &str,
    ignores: RegexSet,
    reader: R,
    writer: W,
) {
    let lock: Arc<Mutex<Vec<(String, i64, i32)>>> = Arc::new(Mutex::new(vec![]));
    let lock_clone = lock.clone();

    let sync_count: Arc<Mutex<(u32, u32)>> = Arc::new(Mutex::new((0, 0)));

    let base_dir_clone = base_dir.to_owned();
    let log_clone = log.clone();
    let sync_count_clone = sync_count.clone();
    let child_1 = thread::spawn(move || {
        run_local_watcher(
            &log_clone,
            &base_dir_clone,
            &ignores,
            writer,
            lock_clone,
            sync_count_clone,
        );
    });

    let base_dir_clone = base_dir.to_owned();
    let log_clone = log.clone();
    let sync_count_clone = sync_count.clone();
    let child_2 = thread::spawn(move || {
        run_remote_listener(&log_clone, &base_dir_clone, reader, lock, sync_count_clone);
    });

    let log_clone = log.clone();
    let (status_log_tx, status_log_rx) = mpsc::channel();
    let child_3 = thread::spawn(move || {
        run_status_logger(&log_clone, sync_count, &status_log_rx);
    });

    info!(log, "Ready!");

    let _ = child_1.join();
    let _ = child_2.join();
    status_log_tx.send(()).unwrap_or_default();
    let _ = child_3.join();
    info!(log, "BindRS Stopping");
}

fn run_local_watcher<W: Write>(
    log: &Logger,
    base_dir: &str,
    ingores: &RegexSet,
    writer: W,
    lock: Arc<Mutex<Vec<(String, i64, i32)>>>,
    sync_count: Arc<Mutex<(u32, u32)>>,
) {
    let mut writer = BufWriter::new(writer);
    let mut watcher = BindrsWatcher::new(base_dir, ingores);
    watcher.watch(log);
    let rx = watcher.rx.unwrap_or_else(|| {
        helpers::log_error_and_exit(log, "Couldn't get local receive channel off local watcher");
        panic!();
    });

    loop {
        let (a, p) = rx.recv().unwrap_or_else(|e| {
            helpers::log_error_and_exit(
                log,
                &format!("Failed to receive message from local watcher: {}", e),
            );
            panic!(e)
        });
        let full_str_path = format!("{}/{}", base_dir, p);
        let full_path = Path::new(&full_str_path);

        if a == FileAction::CreateUpdate && full_path.is_dir() {
            continue;
        }

        let p_clone = p.clone();

        {
            let mut recent_files = lock.lock().unwrap_or_else(|_| {
                helpers::log_error_and_exit(log, "Failed to aquire local fs lock, lock poisoned");
                panic!()
            });
            let (now_s, now_nano_s) = {
                let now_spec = time::now().to_timespec();
                (now_spec.sec, now_spec.nsec)
            };

            recent_files.retain(|&(_, ref time_s, ref time_nano_s)| {
                if now_s - time_s > 1 {
                    false
                } else if now_s - time_s == 1 {
                    now_nano_s - time_nano_s + 1000000000 /* 1e9 */ < 500000000 // 5e8
                } else {
                    now_nano_s - time_nano_s < 500000000 // 5e8
                }
            });

            if recent_files.iter().map(|&(ref path, _, _)| path).any(
                |&ref path| &p_clone == path,
            )
            {
                continue;
            }
        }

        let _guard = lock.lock().unwrap_or_else(|_| {
            helpers::log_error_and_exit(log, "Failed to aquire local fs lock, lock poisoned");
            panic!()
        });

        if a == FileAction::CreateUpdate && !full_path.exists() {
            debug!(log, "Skipping sending {} as file does not exist", p);
        } else {
            let bf = BoundFile::build_from_path_action(base_dir, p, a);
            debug!(log, "Sending {} to remote", bf.path);
            bf.to_writer(&mut writer);

            {
                let mut synced_nums = sync_count.lock().unwrap_or_else(|_| {
                    helpers::log_error_and_exit(
                        log,
                        "Failed to aquire sync count lock, lock poisoned",
                    );
                    panic!()
                });
                synced_nums.0 += 1;
            }
        }
    }
}

fn run_remote_listener<R: Read>(
    log: &Logger,
    base_dir: &str,
    reader: R,
    lock: Arc<Mutex<Vec<(String, i64, i32)>>>,
    sync_count: Arc<Mutex<(u32, u32)>>,
) {
    let mut reader = BufReader::new(reader);
    loop {
        let bf = BoundFile::from_reader(&mut reader);
        let mut recent_files = lock.lock().unwrap_or_else(|_| {
            helpers::log_error_and_exit(log, "Failed to aquire local fs lock, lock poisoned");
            panic!()
        });
        debug!(log, "Receiving {} from remote", bf.path);
        bf.save_to_disk(base_dir);

        let (now_s, now_nano_s) = {
            let now_spec = time::now().to_timespec();
            (now_spec.sec, now_spec.nsec)
        };
        recent_files.push((bf.path, now_s, now_nano_s));

        {
            let mut synced_nums = sync_count.lock().unwrap_or_else(|_| {
                helpers::log_error_and_exit(log, "Failed to aquire sync count lock, lock poisoned");
                panic!()
            });
            synced_nums.1 += 1;
        }
    }
}

fn run_status_logger(log: &Logger, sync_count: Arc<Mutex<(u32, u32)>>, rx: &Receiver<()>) {
    loop {
        sleep(Duration::from_millis(1000));
        match rx.try_recv() {
            Ok(_) |
            Err(TryRecvError::Disconnected) => break,
            Err(TryRecvError::Empty) => (),
        }

        {
            let mut synced_nums = sync_count.lock().unwrap_or_else(|_| {
                helpers::log_error_and_exit(log, "Failed to aquire sync count lock, lock poisoned");
                panic!()
            });

            let to_log = synced_nums.0 > 0 || synced_nums.1 > 0;
            let mut message: Vec<String> = vec![];

            if synced_nums.0 > 0 {
                message.push(format!("Sent {} file/s.", synced_nums.0));
            }

            if synced_nums.1 > 0 {
                message.push(format!("Received {} file/s.", synced_nums.1));
            }

            if to_log {
                info!(log, "{}", message.join(" "));
                *synced_nums = (0, 0)
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::ast::{Ast, AstBuilder, AstKey, Primitive, RequestParameters};
use crate::build_ast::{build_fragment, build_operation, build_request};
use crate::constants::CODEGEN_CONSTANTS;

use graphql_ir::{FragmentDefinition, OperationDefinition};
use schema::Schema;

use fnv::{FnvBuildHasher, FnvHashSet};
use indexmap::IndexMap;
use interner::StringKey;
use std::fmt::{Result as FmtResult, Write};

pub struct Printer {
    builder: AstBuilder,
}

type VariableDefinitions = IndexMap<AstKey, String, FnvBuildHasher>;
struct DedupedJSONPrinter<'b> {
    variable_definitions: VariableDefinitions,
    duplicates: FnvHashSet<AstKey>,
    builder: &'b AstBuilder,
    root_key: AstKey,
}

impl<'b> DedupedJSONPrinter<'b> {
    fn new(builder: &'b AstBuilder, root_key: AstKey) -> Self {
        let mut visited = Default::default();
        let mut duplicates = Default::default();
        Self::collect_value_duplicates(&mut visited, &mut duplicates, builder, root_key);
        Self {
            variable_definitions: Default::default(),
            duplicates,
            builder,
            root_key,
        }
    }

    fn new_without_dedupe(builder: &'b AstBuilder, root_key: AstKey) -> Self {
        Self {
            variable_definitions: Default::default(),
            duplicates: Default::default(),
            builder,
            root_key,
        }
    }

    /// We don't dedupe in an already deduped AST unless the duplicate
    /// also appears on a subtree that's not a duplicate
    /// Input:
    /// [
    ///     [{a: 1}, {b:2}],
    ///     [{a: 1}, {b:2}],
    ///     {b: 2}
    /// ]
    /// Output:
    /// v0 = {b: 2};
    /// v1 = [{a: 1}, v0];
    fn collect_value_duplicates(
        visited: &mut FnvHashSet<AstKey>,
        duplicates: &mut FnvHashSet<AstKey>,
        builder: &AstBuilder,
        key: AstKey,
    ) {
        if !visited.insert(key) {
            duplicates.insert(key);
            return;
        }
        match builder.lookup(key) {
            Ast::Array(array) => {
                for val in array {
                    if let Primitive::Key(key) = val {
                        Self::collect_value_duplicates(visited, duplicates, builder, *key);
                    }
                }
            }
            Ast::Object(object) => {
                for (_, val) in object {
                    if let Primitive::Key(key) = val {
                        Self::collect_value_duplicates(visited, duplicates, builder, *key);
                    }
                }
            }
        }
    }

    fn print(mut self) -> String {
        let mut result = String::new();
        self.print_ast(&mut result, self.root_key, 0, false)
            .unwrap();
        if self.variable_definitions.is_empty() {
            result
        } else {
            let mut with_variables = String::new();
            with_variables.push_str("(function(){\nvar ");
            let last = self.variable_definitions.len() - 1;
            for (i, (_, value)) in self.variable_definitions.drain(..).enumerate() {
                writeln!(
                    &mut with_variables,
                    "v{} = {}{}",
                    i,
                    value,
                    if i == last { ";" } else { "," }
                )
                .unwrap();
            }
            write!(&mut with_variables, "return {};\n}})()", result).unwrap();
            with_variables
        }
    }

    fn print_ast(
        &mut self,
        f: &mut String,
        key: AstKey,
        indent: usize,
        is_dedupe_var: bool,
    ) -> FmtResult {
        // Only use variable references at depth beyond the top level.
        if indent > 0 && self.duplicates.contains(&key) {
            let v = if self.variable_definitions.contains_key(&key) {
                self.variable_definitions.get_full(&key).unwrap().0
            } else {
                let mut variable = String::new();
                self.print_ast(&mut variable, key, 0, true)?;
                let v = self.variable_definitions.len();
                self.variable_definitions.insert(key, variable);
                v
            };
            return write!(f, "(v{}/*: any*/)", v);
        }

        let ast = self.builder.lookup(key);
        match ast {
            Ast::Object(object) => {
                if object.is_empty() {
                    write!(f, "{{}}")
                } else {
                    let next_indent = indent + 1;
                    writeln!(f, "{{")?;
                    for (i, (key, value)) in object.iter().enumerate() {
                        print_indentation(f, next_indent)?;
                        write!(f, "\"{}\": ", key.lookup(),)?;
                        self.print_primitive(f, value, next_indent, is_dedupe_var)?;
                        if i < object.len() - 1 {
                            writeln!(f, ",")?;
                        } else {
                            writeln!(f)?;
                        }
                    }
                    print_indentation(f, indent)?;
                    write!(f, "}}")
                }
            }
            Ast::Array(array) => {
                if array.is_empty() {
                    if is_dedupe_var {
                        // Empty arrays can only have one inferred flow type and then conflict if
                        // used in different places, this is unsound if we would write to them but
                        // this whole module is based on the idea of a read only JSON tree.
                        write!(f, "([]/*: any*/)")
                    } else {
                        write!(f, "[]")
                    }
                } else {
                    writeln!(f, "[")?;
                    let next_indent = indent + 1;
                    for (i, value) in array.iter().enumerate() {
                        print_indentation(f, indent + 1)?;
                        self.print_primitive(f, value, next_indent, is_dedupe_var)?;
                        if i < array.len() - 1 {
                            writeln!(f, ",")?;
                        } else {
                            writeln!(f)?;
                        }
                    }
                    print_indentation(f, indent)?;
                    write!(f, "]")
                }
            }
        }
    }

    fn print_primitive(
        &mut self,
        f: &mut String,
        primitive: &Primitive,
        indent: usize,
        is_dedupe_var: bool,
    ) -> FmtResult {
        match primitive {
            Primitive::Null => write!(f, "null"),
            Primitive::Bool(b) => write!(f, "{}", if *b { "true" } else { "false" }),
            Primitive::RawString(str) => write!(f, "\"{}\"", str),
            Primitive::String(key) => write!(f, "\"{}\"", key),
            Primitive::Float(value) => write!(f, "{}", value.as_float()),
            Primitive::Int(value) => write!(f, "{}", value),
            Primitive::Key(key) => self.print_ast(f, *key, indent, is_dedupe_var),
            Primitive::StorageKey(field_name, key) => {
                print_static_storage_key(f, &self.builder, *field_name, *key)
            }
        }
    }
}

impl Default for Printer {
    fn default() -> Self {
        Self {
            builder: AstBuilder::default(),
        }
    }
}

pub fn print_operation(schema: &Schema, operation: &OperationDefinition) -> String {
    let mut builder = AstBuilder::default();
    let key = build_operation(schema, &mut builder, operation);
    let printer = DedupedJSONPrinter::new_without_dedupe(&builder, key);
    printer.print()
}

pub fn print_fragment(schema: &Schema, fragment: &FragmentDefinition) -> String {
    let mut builder = AstBuilder::default();
    let key = build_fragment(schema, &mut builder, fragment);
    let printer = DedupedJSONPrinter::new_without_dedupe(&builder, key);
    printer.print()
}

pub fn print_request(
    schema: &Schema,
    operation: &OperationDefinition,
    fragment: &FragmentDefinition,
    request_parameters: RequestParameters,
) -> String {
    let mut builder = AstBuilder::default();
    let key = build_request(
        schema,
        &mut builder,
        operation,
        fragment,
        request_parameters,
    );
    let printer = DedupedJSONPrinter::new_without_dedupe(&builder, key);
    printer.print()
}

impl Printer {
    pub fn print_request_deduped(
        &mut self,
        schema: &Schema,
        operation: &OperationDefinition,
        fragment: &FragmentDefinition,
        request_parameters: RequestParameters,
    ) -> String {
        let key = build_request(
            schema,
            &mut self.builder,
            operation,
            fragment,
            request_parameters,
        );
        let deduped_printer = DedupedJSONPrinter::new(&self.builder, key);
        deduped_printer.print()
    }

    pub fn print_operation_deduped(
        &mut self,
        schema: &Schema,
        operation: &OperationDefinition,
    ) -> String {
        let key = build_operation(schema, &mut self.builder, operation);
        let deduped_printer = DedupedJSONPrinter::new(&self.builder, key);
        deduped_printer.print()
    }

    pub fn print_fragment_deduped(
        &mut self,
        schema: &Schema,
        fragment: &FragmentDefinition,
    ) -> String {
        let key = build_fragment(schema, &mut self.builder, fragment);
        let deduped_printer = DedupedJSONPrinter::new(&self.builder, key);
        deduped_printer.print()
    }
}

fn print_indentation<W: Write>(dest_buffer: &mut W, indent: usize) -> FmtResult {
    for _ in 0..indent {
        write!(dest_buffer, "  ")?;
    }
    Ok(())
}

/// Pre-computes storage key if possible and advantageous. Storage keys are
/// generated for fields with supplied arguments that are all statically known
/// (ie. literals, no variables) at build time.
fn print_static_storage_key(
    f: &mut String,
    builder: &AstBuilder,
    field_name: StringKey,
    args_key: AstKey,
) -> FmtResult {
    // TODO (T64585375): JS compiler has an option to force a storageKey.
    let args = builder.lookup(args_key).assert_array();
    write_static_storage_key(f, builder, field_name, args)
}

fn write_static_storage_key(
    f: &mut String,
    builder: &AstBuilder,
    field_name: StringKey,
    args: &[Primitive],
) -> FmtResult {
    write!(f, "\"{}(", field_name)?;
    for arg_key in args {
        let arg = builder.lookup(arg_key.assert_key()).assert_object();
        let (_, name) = arg
            .iter()
            .find(|(key, _)| *key == CODEGEN_CONSTANTS.name)
            .expect("Expected `name` to exist");
        let name = name.assert_string();
        write!(f, "{}:", name)?;
        write_argument_value(f, builder, arg)?;
        f.push(',');
    }
    f.pop(); // args won't be empty
    f.push_str(")\"");
    Ok(())
}

fn write_argument_value(
    f: &mut String,
    builder: &AstBuilder,
    arg: &[(StringKey, Primitive)],
) -> FmtResult {
    let (_, key) = arg
        .iter()
        .find(|(key, _)| *key == CODEGEN_CONSTANTS.kind)
        .expect("Expected `kind` to exist");
    let key = key.assert_string();
    // match doesn't allow `CODEGEN_CONSTANTS.<>` on the match arm, falling back to if statements
    if key == CODEGEN_CONSTANTS.literal {
        let (_, literal) = arg
            .iter()
            .find(|(key, _)| *key == CODEGEN_CONSTANTS.value)
            .expect("Expected `name` to exist");
        write_constant_value(f, builder, literal)?;
    } else if key == CODEGEN_CONSTANTS.list_value {
        let (_, items) = arg
            .iter()
            .find(|(key, _)| *key == CODEGEN_CONSTANTS.items)
            .expect("Expected `items` to exist");
        let array = builder.lookup(items.assert_key()).assert_array();

        f.push('[');
        for key in array {
            let object = builder.lookup(key.assert_key()).assert_object();
            write_argument_value(f, builder, object)?;
            f.push(',');
        }
        if !array.is_empty() {
            f.pop();
        }
        f.push(']');
    } else {
        // We filtered out Variables, here it should only be ObjectValue
        let (_, value) = arg
            .iter()
            .find(|(key, _)| *key == CODEGEN_CONSTANTS.fields)
            .expect("Expected `fields` to exist");
        let array = builder.lookup(value.assert_key()).assert_array();

        f.push('{');
        for key in array {
            let (_, name) = arg
                .iter()
                .find(|(key, _)| *key == CODEGEN_CONSTANTS.name)
                .expect("Expected `name` to exist");
            let name = name.assert_string();
            write!(f, "\\\"{}\\\":", name)?;
            let object = builder.lookup(key.assert_key()).assert_object();
            write_argument_value(f, builder, object)?;
            f.push(',');
        }
        if !array.is_empty() {
            f.pop();
        }
        f.push('}');
    }
    Ok(())
}

fn write_constant_value(f: &mut String, builder: &AstBuilder, value: &Primitive) -> FmtResult {
    match value {
        Primitive::Bool(b) => write!(f, "{}", if *b { "true" } else { "false" }),
        Primitive::String(key) => write!(f, "\\\"{}\\\"", key),
        Primitive::Float(value) => write!(f, "{}", value.as_float()),
        Primitive::Int(value) => write!(f, "{}", value),
        Primitive::Key(key) => {
            let ast = builder.lookup(*key);
            match ast {
                Ast::Array(arr) => {
                    f.push('[');
                    for value in arr {
                        write_constant_value(f, builder, value)?;
                        f.push(',');
                    }
                    if !arr.is_empty() {
                        f.pop();
                    }
                    f.push(']');
                    Ok(())
                }
                Ast::Object(obj) => {
                    f.push('{');
                    for (name, value) in obj {
                        write!(f, "\\\"{}\\\":", name)?;
                        write_constant_value(f, builder, value)?;
                        f.push(',');
                    }
                    if !obj.is_empty() {
                        f.pop();
                    }
                    f.push('}');
                    Ok(())
                }
            }
        }
        Primitive::Null => {
            f.push_str("null");
            Ok(())
        }
        Primitive::StorageKey(_, _) => panic!("Unexpected StorageKey"),
        Primitive::RawString(_) => panic!("Unexpected RawString"),
    }
}
<commit_msg>Fix storageKey printing<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::ast::{Ast, AstBuilder, AstKey, Primitive, RequestParameters};
use crate::build_ast::{build_fragment, build_operation, build_request};
use crate::constants::CODEGEN_CONSTANTS;

use graphql_ir::{FragmentDefinition, OperationDefinition};
use schema::Schema;

use fnv::{FnvBuildHasher, FnvHashSet};
use indexmap::IndexMap;
use interner::StringKey;
use std::fmt::{Result as FmtResult, Write};

pub struct Printer {
    builder: AstBuilder,
}

type VariableDefinitions = IndexMap<AstKey, String, FnvBuildHasher>;
struct DedupedJSONPrinter<'b> {
    variable_definitions: VariableDefinitions,
    duplicates: FnvHashSet<AstKey>,
    builder: &'b AstBuilder,
    root_key: AstKey,
}

impl<'b> DedupedJSONPrinter<'b> {
    fn new(builder: &'b AstBuilder, root_key: AstKey) -> Self {
        let mut visited = Default::default();
        let mut duplicates = Default::default();
        Self::collect_value_duplicates(&mut visited, &mut duplicates, builder, root_key);
        Self {
            variable_definitions: Default::default(),
            duplicates,
            builder,
            root_key,
        }
    }

    fn new_without_dedupe(builder: &'b AstBuilder, root_key: AstKey) -> Self {
        Self {
            variable_definitions: Default::default(),
            duplicates: Default::default(),
            builder,
            root_key,
        }
    }

    /// We don't dedupe in an already deduped AST unless the duplicate
    /// also appears on a subtree that's not a duplicate
    /// Input:
    /// [
    ///     [{a: 1}, {b:2}],
    ///     [{a: 1}, {b:2}],
    ///     {b: 2}
    /// ]
    /// Output:
    /// v0 = {b: 2};
    /// v1 = [{a: 1}, v0];
    fn collect_value_duplicates(
        visited: &mut FnvHashSet<AstKey>,
        duplicates: &mut FnvHashSet<AstKey>,
        builder: &AstBuilder,
        key: AstKey,
    ) {
        if !visited.insert(key) {
            duplicates.insert(key);
            return;
        }
        match builder.lookup(key) {
            Ast::Array(array) => {
                for val in array {
                    if let Primitive::Key(key) = val {
                        Self::collect_value_duplicates(visited, duplicates, builder, *key);
                    }
                }
            }
            Ast::Object(object) => {
                for (_, val) in object {
                    if let Primitive::Key(key) = val {
                        Self::collect_value_duplicates(visited, duplicates, builder, *key);
                    }
                }
            }
        }
    }

    fn print(mut self) -> String {
        let mut result = String::new();
        self.print_ast(&mut result, self.root_key, 0, false)
            .unwrap();
        if self.variable_definitions.is_empty() {
            result
        } else {
            let mut with_variables = String::new();
            with_variables.push_str("(function(){\nvar ");
            let last = self.variable_definitions.len() - 1;
            for (i, (_, value)) in self.variable_definitions.drain(..).enumerate() {
                writeln!(
                    &mut with_variables,
                    "v{} = {}{}",
                    i,
                    value,
                    if i == last { ";" } else { "," }
                )
                .unwrap();
            }
            write!(&mut with_variables, "return {};\n}})()", result).unwrap();
            with_variables
        }
    }

    fn print_ast(
        &mut self,
        f: &mut String,
        key: AstKey,
        indent: usize,
        is_dedupe_var: bool,
    ) -> FmtResult {
        // Only use variable references at depth beyond the top level.
        if indent > 0 && self.duplicates.contains(&key) {
            let v = if self.variable_definitions.contains_key(&key) {
                self.variable_definitions.get_full(&key).unwrap().0
            } else {
                let mut variable = String::new();
                self.print_ast(&mut variable, key, 0, true)?;
                let v = self.variable_definitions.len();
                self.variable_definitions.insert(key, variable);
                v
            };
            return write!(f, "(v{}/*: any*/)", v);
        }

        let ast = self.builder.lookup(key);
        match ast {
            Ast::Object(object) => {
                if object.is_empty() {
                    write!(f, "{{}}")
                } else {
                    let next_indent = indent + 1;
                    writeln!(f, "{{")?;
                    for (i, (key, value)) in object.iter().enumerate() {
                        print_indentation(f, next_indent)?;
                        write!(f, "\"{}\": ", key.lookup(),)?;
                        self.print_primitive(f, value, next_indent, is_dedupe_var)?;
                        if i < object.len() - 1 {
                            writeln!(f, ",")?;
                        } else {
                            writeln!(f)?;
                        }
                    }
                    print_indentation(f, indent)?;
                    write!(f, "}}")
                }
            }
            Ast::Array(array) => {
                if array.is_empty() {
                    if is_dedupe_var {
                        // Empty arrays can only have one inferred flow type and then conflict if
                        // used in different places, this is unsound if we would write to them but
                        // this whole module is based on the idea of a read only JSON tree.
                        write!(f, "([]/*: any*/)")
                    } else {
                        write!(f, "[]")
                    }
                } else {
                    writeln!(f, "[")?;
                    let next_indent = indent + 1;
                    for (i, value) in array.iter().enumerate() {
                        print_indentation(f, indent + 1)?;
                        self.print_primitive(f, value, next_indent, is_dedupe_var)?;
                        if i < array.len() - 1 {
                            writeln!(f, ",")?;
                        } else {
                            writeln!(f)?;
                        }
                    }
                    print_indentation(f, indent)?;
                    write!(f, "]")
                }
            }
        }
    }

    fn print_primitive(
        &mut self,
        f: &mut String,
        primitive: &Primitive,
        indent: usize,
        is_dedupe_var: bool,
    ) -> FmtResult {
        match primitive {
            Primitive::Null => write!(f, "null"),
            Primitive::Bool(b) => write!(f, "{}", if *b { "true" } else { "false" }),
            Primitive::RawString(str) => write!(f, "\"{}\"", str),
            Primitive::String(key) => write!(f, "\"{}\"", key),
            Primitive::Float(value) => write!(f, "{}", value.as_float()),
            Primitive::Int(value) => write!(f, "{}", value),
            Primitive::Key(key) => self.print_ast(f, *key, indent, is_dedupe_var),
            Primitive::StorageKey(field_name, key) => {
                print_static_storage_key(f, &self.builder, *field_name, *key)
            }
        }
    }
}

impl Default for Printer {
    fn default() -> Self {
        Self {
            builder: AstBuilder::default(),
        }
    }
}

pub fn print_operation(schema: &Schema, operation: &OperationDefinition) -> String {
    let mut builder = AstBuilder::default();
    let key = build_operation(schema, &mut builder, operation);
    let printer = DedupedJSONPrinter::new_without_dedupe(&builder, key);
    printer.print()
}

pub fn print_fragment(schema: &Schema, fragment: &FragmentDefinition) -> String {
    let mut builder = AstBuilder::default();
    let key = build_fragment(schema, &mut builder, fragment);
    let printer = DedupedJSONPrinter::new_without_dedupe(&builder, key);
    printer.print()
}

pub fn print_request(
    schema: &Schema,
    operation: &OperationDefinition,
    fragment: &FragmentDefinition,
    request_parameters: RequestParameters,
) -> String {
    let mut builder = AstBuilder::default();
    let key = build_request(
        schema,
        &mut builder,
        operation,
        fragment,
        request_parameters,
    );
    let printer = DedupedJSONPrinter::new_without_dedupe(&builder, key);
    printer.print()
}

impl Printer {
    pub fn print_request_deduped(
        &mut self,
        schema: &Schema,
        operation: &OperationDefinition,
        fragment: &FragmentDefinition,
        request_parameters: RequestParameters,
    ) -> String {
        let key = build_request(
            schema,
            &mut self.builder,
            operation,
            fragment,
            request_parameters,
        );
        let deduped_printer = DedupedJSONPrinter::new(&self.builder, key);
        deduped_printer.print()
    }

    pub fn print_operation_deduped(
        &mut self,
        schema: &Schema,
        operation: &OperationDefinition,
    ) -> String {
        let key = build_operation(schema, &mut self.builder, operation);
        let deduped_printer = DedupedJSONPrinter::new(&self.builder, key);
        deduped_printer.print()
    }

    pub fn print_fragment_deduped(
        &mut self,
        schema: &Schema,
        fragment: &FragmentDefinition,
    ) -> String {
        let key = build_fragment(schema, &mut self.builder, fragment);
        let deduped_printer = DedupedJSONPrinter::new(&self.builder, key);
        deduped_printer.print()
    }
}

fn print_indentation<W: Write>(dest_buffer: &mut W, indent: usize) -> FmtResult {
    for _ in 0..indent {
        write!(dest_buffer, "  ")?;
    }
    Ok(())
}

/// Pre-computes storage key if possible and advantageous. Storage keys are
/// generated for fields with supplied arguments that are all statically known
/// (ie. literals, no variables) at build time.
fn print_static_storage_key(
    f: &mut String,
    builder: &AstBuilder,
    field_name: StringKey,
    args_key: AstKey,
) -> FmtResult {
    // TODO (T64585375): JS compiler has an option to force a storageKey.
    let args = builder.lookup(args_key).assert_array();
    write_static_storage_key(f, builder, field_name, args)
}

fn write_static_storage_key(
    f: &mut String,
    builder: &AstBuilder,
    field_name: StringKey,
    args: &[Primitive],
) -> FmtResult {
    write!(f, "\"{}(", field_name)?;
    for arg_key in args {
        let arg = builder.lookup(arg_key.assert_key()).assert_object();
        let (_, name) = arg
            .iter()
            .find(|(key, _)| *key == CODEGEN_CONSTANTS.name)
            .expect("Expected `name` to exist");
        let name = name.assert_string();
        write!(f, "{}:", name)?;
        write_argument_value(f, builder, arg)?;
        f.push(',');
    }
    f.pop(); // args won't be empty
    f.push_str(")\"");
    Ok(())
}

fn write_argument_value(
    f: &mut String,
    builder: &AstBuilder,
    arg: &[(StringKey, Primitive)],
) -> FmtResult {
    let (_, key) = arg
        .iter()
        .find(|(key, _)| *key == CODEGEN_CONSTANTS.kind)
        .expect("Expected `kind` to exist");
    let key = key.assert_string();
    // match doesn't allow `CODEGEN_CONSTANTS.<>` on the match arm, falling back to if statements
    if key == CODEGEN_CONSTANTS.literal {
        let (_, literal) = arg
            .iter()
            .find(|(key, _)| *key == CODEGEN_CONSTANTS.value)
            .expect("Expected `name` to exist");
        write_constant_value(f, builder, literal)?;
    } else if key == CODEGEN_CONSTANTS.list_value {
        let (_, items) = arg
            .iter()
            .find(|(key, _)| *key == CODEGEN_CONSTANTS.items)
            .expect("Expected `items` to exist");
        let array = builder.lookup(items.assert_key()).assert_array();

        f.push('[');
        for key_or_null in array {
            match key_or_null {
                Primitive::Null => f.push_str("null,"),
                Primitive::Key(key) => {
                    let object = builder.lookup(*key).assert_object();
                    write_argument_value(f, builder, object)?;
                    f.push(',');
                }
                _ => panic!("Expected an object key or null"),
            }
        }
        if !array.is_empty() {
            f.pop();
        }
        f.push(']');
    } else {
        // We filtered out Variables, here it should only be ObjectValue
        let (_, value) = arg
            .iter()
            .find(|(key, _)| *key == CODEGEN_CONSTANTS.fields)
            .expect("Expected `fields` to exist");
        let array = builder.lookup(value.assert_key()).assert_array();

        f.push('{');
        for key in array {
            let (_, name) = arg
                .iter()
                .find(|(key, _)| *key == CODEGEN_CONSTANTS.name)
                .expect("Expected `name` to exist");
            let name = name.assert_string();
            write!(f, "\\\"{}\\\":", name)?;
            let object = builder.lookup(key.assert_key()).assert_object();
            write_argument_value(f, builder, object)?;
            f.push(',');
        }
        if !array.is_empty() {
            f.pop();
        }
        f.push('}');
    }
    Ok(())
}

fn write_constant_value(f: &mut String, builder: &AstBuilder, value: &Primitive) -> FmtResult {
    match value {
        Primitive::Bool(b) => write!(f, "{}", if *b { "true" } else { "false" }),
        Primitive::String(key) => write!(f, "\\\"{}\\\"", key),
        Primitive::Float(value) => write!(f, "{}", value.as_float()),
        Primitive::Int(value) => write!(f, "{}", value),
        Primitive::Key(key) => {
            let ast = builder.lookup(*key);
            match ast {
                Ast::Array(arr) => {
                    f.push('[');
                    for value in arr {
                        write_constant_value(f, builder, value)?;
                        f.push(',');
                    }
                    if !arr.is_empty() {
                        f.pop();
                    }
                    f.push(']');
                    Ok(())
                }
                Ast::Object(obj) => {
                    f.push('{');
                    for (name, value) in obj {
                        write!(f, "\\\"{}\\\":", name)?;
                        write_constant_value(f, builder, value)?;
                        f.push(',');
                    }
                    if !obj.is_empty() {
                        f.pop();
                    }
                    f.push('}');
                    Ok(())
                }
            }
        }
        Primitive::Null => {
            f.push_str("null");
            Ok(())
        }
        Primitive::StorageKey(_, _) => panic!("Unexpected StorageKey"),
        Primitive::RawString(_) => panic!("Unexpected RawString"),
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Combinations with and without replacement.

use std::cmp;

/// Calculate the number of combinations when choosing
/// k elements from n elements without replacement.
/// This is also known as n over k, or the binomial coefficient.
pub fn combinations(n: u64, k: u64) -> f64 {
    if k > n {
        0.0
    }
    else {
        let mut comb = 1.0;
        for j in 0..cmp::min(k, n-k) {
            comb /= (j + 1) as f64;
            comb *= (n - j) as f64;
        }
        comb
    }
}

/// Calculate the number of combinations when choosing
/// k elements from n elements with replacement.
pub fn combinations_with_repl(n: u64, k: u64) -> f64 {
    combinations(n + k - 1, k)
}

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

    #[test]
    fn test_comb() {
        assert_eq!(combinations(10, 3), 120.0);
        assert_eq!(combinations_with_repl(10, 3), 220.0);
        assert_eq!(combinations(200, 10), 22451004309013280.0);
    }
}
<commit_msg>Introduce scaled combinations.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Combinations with and without replacement.

use std::cmp;
use std::f64;

/// Calculate the number of combinations when choosing
/// k elements from n elements without replacement, multiplied by a scaling factor.
pub fn scaled_combinations(n: u64, k: u64, scale: f64) -> f64 {
    if k > n {
        0.0
    }
    else {
        let mut comb = scale;
        for j in 0..cmp::min(k, n-k) {
            comb /= (j + 1) as f64;
            comb *= (n - j) as f64;
        }
        comb
    }
}

/// Calculate the number of combinations when choosing
/// k elements from n elements without replacement.
/// This is also known as n over k, or the binomial coefficient.
pub fn combinations(n: u64, k: u64) -> f64 {
    scaled_combinations(n, k, 1.0)
}

/// Calculate the number of combinations when choosing
/// k elements from n elements with replacement.
pub fn combinations_with_repl(n: u64, k: u64) -> f64 {
    combinations(n + k - 1, k)
}

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

    #[test]
    fn test_comb() {
        assert_eq!(combinations(10, 3), 120.0);
        assert_eq!(combinations_with_repl(10, 3), 220.0);
        assert_eq!(combinations(200, 10), 22451004309013280.0);
    }

    #[test]
    fn test_comb_scaled() {
        assert!((scaled_combinations(150, 80, 1e-5) - 6.6643938163479384e+38).abs() < 0.0000001);
    }
}
<|endoftext|>


<commit_before>use serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

pub struct JsonHeaderParser {
    spec: Option<FileHeaderSpec>,
}

impl JsonHeaderParser {

    pub fn new(spec: Option<FileHeaderSpec>) -> JsonHeaderParser {
        JsonHeaderParser {
            spec: spec
        }
    }

}

impl FileHeaderParser for JsonHeaderParser {

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if string.is_some() {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(content) = fromstr {
                Ok(visit_json(&content))
            } else {
                Err(ParserError::short("Unknown JSON parser error", s.clone(), 0))
            }
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut s = Vec::<u8>::new();
        {
            let mut ser = Serializer::pretty(&mut s);
            data.serialize(&mut ser);
        }

        String::from_utf8(s).or(
            Err(ParserError::short("Cannot parse utf8 bytes",
                                   String::from("<not printable>"),
                                   0)))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(&i)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            FileHeaderData::Map{
                keys: btree.clone().iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k.clone(),
                        value: Box::new(visit_json(v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => ks.serialize(ser),
            &FileHeaderData::Key{name: ref n, value: ref v}   => {
                let mut hm = HashMap::new();
                hm.insert(n, v);
                hm.serialize(ser)
            }
        }
    }

}
<commit_msg>Fix JsonHeaderParser::visit_json()<commit_after>use serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

pub struct JsonHeaderParser {
    spec: Option<FileHeaderSpec>,
}

impl JsonHeaderParser {

    pub fn new(spec: Option<FileHeaderSpec>) -> JsonHeaderParser {
        JsonHeaderParser {
            spec: spec
        }
    }

}

impl FileHeaderParser for JsonHeaderParser {

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if string.is_some() {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(content) = fromstr {
                Ok(visit_json(&content))
            } else {
                Err(ParserError::short("Unknown JSON parser error", s.clone(), 0))
            }
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut s = Vec::<u8>::new();
        {
            let mut ser = Serializer::pretty(&mut s);
            data.serialize(&mut ser);
        }

        String::from_utf8(s).or(
            Err(ParserError::short("Cannot parse utf8 bytes",
                                   String::from("<not printable>"),
                                   0)))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(&i)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            let btree = btree.clone();
            FileHeaderData::Map{
                keys: btree.into_iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k,
                        value: Box::new(visit_json(&v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => ks.serialize(ser),
            &FileHeaderData::Key{name: ref n, value: ref v}   => {
                let mut hm = HashMap::new();
                hm.insert(n, v);
                hm.serialize(ser)
            }
        }
    }

}
<|endoftext|>


<commit_before>// spell-checker:ignore (words) defaultcheck nocheck

use crate::common::util::*;

#[test]
fn ab_no_args() {
    new_ucmd!()
        .args(&["a", "b"])
        .succeeds()
        .stdout_only_fixture("ab.expected");
}

#[test]
fn ab_dash_one() {
    new_ucmd!()
        .args(&["a", "b", "-1"])
        .succeeds()
        .stdout_only_fixture("ab1.expected");
}

#[test]
fn ab_dash_two() {
    new_ucmd!()
        .args(&["a", "b", "-2"])
        .succeeds()
        .stdout_only_fixture("ab2.expected");
}

#[test]
fn ab_dash_three() {
    new_ucmd!()
        .args(&["a", "b", "-3"])
        .succeeds()
        .stdout_only_fixture("ab3.expected");
}

#[test]
fn a_empty() {
    new_ucmd!()
        .args(&["a", "empty"])
        .succeeds()
        .stdout_only_fixture("aempty.expected"); // spell-checker:disable-line
}

#[test]
fn empty_empty() {
    new_ucmd!()
        .args(&["empty", "empty"])
        .succeeds()
        .stdout_only_fixture("emptyempty.expected"); // spell-checker:disable-line
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn output_delimiter() {
    new_ucmd!()
        .args(&["--output-delimiter=word", "a", "b"])
        .succeeds()
        .stdout_only_fixture("ab_delimiter_word.expected");
}

#[test]
fn output_delimiter_nul() {
    new_ucmd!()
        .args(&["--output-delimiter=", "a", "b"])
        .succeeds()
        .stdout_only_fixture("ab_delimiter_nul.expected");
}

// even though (info) documentation suggests this is an option
// in latest GNU Coreutils comm, it actually is not.
// this test is essentially an alarm in case some well-intending
// developer implements it.
//marked as unimplemented as error message not set yet.
#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn zero_terminated() {
    for param in ["-z", "--zero-terminated"] {
        new_ucmd!()
            .args(&[param, "a", "b"])
            .fails()
            .stderr_only("error to be defined");
    }
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn check_order() {
    new_ucmd!()
        .args(&["--check-order", "bad_order_1", "bad_order_2"])
        .fails()
        .stdout_is_fixture("bad_order12.check_order.expected")
        .stderr_is("error to be defined");
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn nocheck_order() {
    new_ucmd!()
        .args(&["--nocheck-order", "bad_order_1", "bad_order_2"])
        .succeeds()
        .stdout_only_fixture("bad_order12.nocheck_order.expected");
}

// when neither --check-order nor --no-check-order is provided,
// stderr and the error code behaves like check order, but stdout
// behaves like nocheck_order. However with some quirks detailed below.
#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn defaultcheck_order() {
    new_ucmd!()
        .args(&["a", "bad_order_1"])
        .fails()
        .stderr_only("error to be defined");
}

// * the first: if both files are not in order, the default behavior is the only
// behavior that will provide an error message

// * the second: if two rows are paired but are out of order,
// it won't matter if all rows in the two files are exactly the same.
// This is specified in the documentation

#[test]
fn defaultcheck_order_identical_bad_order_files() {
    new_ucmd!()
        .args(&["bad_order_1", "bad_order_1"])
        .succeeds()
        .stdout_only_fixture("bad_order11.defaultcheck_order.expected");
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn defaultcheck_order_two_different_bad_order_files() {
    new_ucmd!()
        .args(&["bad_order_1", "bad_order_2"])
        .fails()
        .stdout_is_fixture("bad_order12.nocheck_order.expected")
        .stderr_is("error to be defined");
}

// * the third: (it is not know whether this is a bug or not)
// for the first incident, and only the first incident,
// where both lines are different and one or both file lines being
// compared are out of order from the preceding line,
// it is ignored and no errors occur.

// * the fourth: (it is not known whether this is a bug or not)
// there are additional, not-yet-understood circumstances where an out-of-order
// pair is ignored and is not counted against the 1 maximum out-of-order line.

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn unintuitive_default_behavior_1() {
    new_ucmd!()
        .args(&["defaultcheck_unintuitive_1", "defaultcheck_unintuitive_2"])
        .succeeds()
        .stdout_only_fixture("defaultcheck_unintuitive.expected");
}

#[ignore] //bug? should help be stdout if not called via -h|--help?
#[test]
fn no_arguments() {
    new_ucmd!().fails().no_stdout().no_stderr();
}

#[ignore] //bug? should help be stdout if not called via -h|--help?
#[test]
fn one_argument() {
    new_ucmd!().arg("a").fails().no_stdout().no_stderr();
}

#[test]
fn test_no_such_file() {
    new_ucmd!()
        .args(&["bogus_file_1", "bogus_file_2"])
        .fails()
        .stderr_only("comm: bogus_file_1: No such file or directory");
}
<commit_msg>comm: enable "output_delimiter" test<commit_after>// spell-checker:ignore (words) defaultcheck nocheck

use crate::common::util::*;

#[test]
fn ab_no_args() {
    new_ucmd!()
        .args(&["a", "b"])
        .succeeds()
        .stdout_only_fixture("ab.expected");
}

#[test]
fn ab_dash_one() {
    new_ucmd!()
        .args(&["a", "b", "-1"])
        .succeeds()
        .stdout_only_fixture("ab1.expected");
}

#[test]
fn ab_dash_two() {
    new_ucmd!()
        .args(&["a", "b", "-2"])
        .succeeds()
        .stdout_only_fixture("ab2.expected");
}

#[test]
fn ab_dash_three() {
    new_ucmd!()
        .args(&["a", "b", "-3"])
        .succeeds()
        .stdout_only_fixture("ab3.expected");
}

#[test]
fn a_empty() {
    new_ucmd!()
        .args(&["a", "empty"])
        .succeeds()
        .stdout_only_fixture("aempty.expected"); // spell-checker:disable-line
}

#[test]
fn empty_empty() {
    new_ucmd!()
        .args(&["empty", "empty"])
        .succeeds()
        .stdout_only_fixture("emptyempty.expected"); // spell-checker:disable-line
}

#[test]
fn output_delimiter() {
    new_ucmd!()
        .args(&["--output-delimiter=word", "a", "b"])
        .succeeds()
        .stdout_only_fixture("ab_delimiter_word.expected");
}

#[test]
fn output_delimiter_nul() {
    new_ucmd!()
        .args(&["--output-delimiter=", "a", "b"])
        .succeeds()
        .stdout_only_fixture("ab_delimiter_nul.expected");
}

// even though (info) documentation suggests this is an option
// in latest GNU Coreutils comm, it actually is not.
// this test is essentially an alarm in case some well-intending
// developer implements it.
//marked as unimplemented as error message not set yet.
#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn zero_terminated() {
    for param in ["-z", "--zero-terminated"] {
        new_ucmd!()
            .args(&[param, "a", "b"])
            .fails()
            .stderr_only("error to be defined");
    }
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn check_order() {
    new_ucmd!()
        .args(&["--check-order", "bad_order_1", "bad_order_2"])
        .fails()
        .stdout_is_fixture("bad_order12.check_order.expected")
        .stderr_is("error to be defined");
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn nocheck_order() {
    new_ucmd!()
        .args(&["--nocheck-order", "bad_order_1", "bad_order_2"])
        .succeeds()
        .stdout_only_fixture("bad_order12.nocheck_order.expected");
}

// when neither --check-order nor --no-check-order is provided,
// stderr and the error code behaves like check order, but stdout
// behaves like nocheck_order. However with some quirks detailed below.
#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn defaultcheck_order() {
    new_ucmd!()
        .args(&["a", "bad_order_1"])
        .fails()
        .stderr_only("error to be defined");
}

// * the first: if both files are not in order, the default behavior is the only
// behavior that will provide an error message

// * the second: if two rows are paired but are out of order,
// it won't matter if all rows in the two files are exactly the same.
// This is specified in the documentation

#[test]
fn defaultcheck_order_identical_bad_order_files() {
    new_ucmd!()
        .args(&["bad_order_1", "bad_order_1"])
        .succeeds()
        .stdout_only_fixture("bad_order11.defaultcheck_order.expected");
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn defaultcheck_order_two_different_bad_order_files() {
    new_ucmd!()
        .args(&["bad_order_1", "bad_order_2"])
        .fails()
        .stdout_is_fixture("bad_order12.nocheck_order.expected")
        .stderr_is("error to be defined");
}

// * the third: (it is not know whether this is a bug or not)
// for the first incident, and only the first incident,
// where both lines are different and one or both file lines being
// compared are out of order from the preceding line,
// it is ignored and no errors occur.

// * the fourth: (it is not known whether this is a bug or not)
// there are additional, not-yet-understood circumstances where an out-of-order
// pair is ignored and is not counted against the 1 maximum out-of-order line.

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn unintuitive_default_behavior_1() {
    new_ucmd!()
        .args(&["defaultcheck_unintuitive_1", "defaultcheck_unintuitive_2"])
        .succeeds()
        .stdout_only_fixture("defaultcheck_unintuitive.expected");
}

#[ignore] //bug? should help be stdout if not called via -h|--help?
#[test]
fn no_arguments() {
    new_ucmd!().fails().no_stdout().no_stderr();
}

#[ignore] //bug? should help be stdout if not called via -h|--help?
#[test]
fn one_argument() {
    new_ucmd!().arg("a").fails().no_stdout().no_stderr();
}

#[test]
fn test_no_such_file() {
    new_ucmd!()
        .args(&["bogus_file_1", "bogus_file_2"])
        .fails()
        .stderr_only("comm: bogus_file_1: No such file or directory");
}
<|endoftext|>