<commit_before>use std::ops::Range;

/// A (set of) dimensions in an array. A `Dimensions` object carries informations
/// about its size, and how to convert a multi-dimensional index to a linear
/// index.
pub trait Dimensions: Clone + PartialEq {
    /// The type to use to index this dimension
    type Index: Copy;
    /// Convert an index to a linear offset for this dimension size
    fn offset(&self, index: Self::Index) -> usize;
    /// Get the number of elements in this dimension
    fn size(&self) -> usize;
}

impl Dimensions for usize {
    type Index = usize;

    #[inline(always)]
    fn offset(&self, index: usize) -> usize {
        assert!(index < *self);
        index
    }

    #[inline(always)]
    fn size(&self) -> usize {
        *self
    }
}

impl Dimensions for Range<usize> {
    type Index = usize;

    #[inline(always)]
    fn offset(&self, index: usize) -> usize {
        assert!(self.start <= index && index < self.end);
        index - self.start
    }

    #[inline(always)]
    fn size(&self) -> usize {
        self.end - self.start
    }
}

impl Dimensions for Range<i32> {
    type Index = i32;

    #[inline(always)]
    fn offset(&self, index: i32) -> usize {
        assert!(self.start <= index && index < self.end);
        assert!(index - self.start > 0);
        (index - self.start) as usize
    }

    #[inline(always)]
    fn size(&self) -> usize {
        (self.end - self.start) as usize
    }
}

impl<A, B> Dimensions for (A, B) where A: Dimensions, B: Dimensions {
    type Index = (A::Index, B::Index);

    #[inline(always)]
    fn offset(&self, index: Self::Index) -> usize {
        self.1.size() * self.0.offset(index.0) + self.1.offset(index.1)
    }

    #[inline(always)]
    fn size(&self) -> usize {
        self.0.size() * self.1.size()
    }
}

impl<A, B, C> Dimensions for (A, B, C) where A: Dimensions, B: Dimensions, C: Dimensions {
    type Index = (A::Index, B::Index, C::Index);

    #[inline(always)]
    fn offset(&self, index: Self::Index) -> usize {
        self.2.size() * (self.1.size() * self.0.offset(index.0) + self.1.offset(index.1)) + self.2.offset(index.2)
    }

    #[inline(always)]
    fn size(&self) -> usize {
        self.0.size() * self.1.size() * self.2.size()
    }
}

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

    mod urange {
        use super::*;
        #[test]
        fn offset() {
            let dim = 4..10;
            assert_eq!(dim.size(), 6);
            assert_eq!(dim.offset(5), 1);
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim() {
            let dim = 4..10;
            dim.offset(11);
        }

        #[test]
        #[should_panic]
        fn smaller_than_dim() {
            let dim = 4..10;
            dim.offset(2);
        }
    }

    mod irange {
        use super::*;
        #[test]
        fn offset() {
            let dim = -4..10;
            assert_eq!(dim.size(), 14);
            assert_eq!(dim.offset(5), 9);
            assert_eq!(dim.offset(-3), 1);
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim() {
            let dim = -4..10;
            dim.offset(11);
        }

        #[test]
        #[should_panic]
        fn smaller_than_dim() {
            let dim = -4..10;
            dim.offset(-6);
        }
    }

    mod dim1 {
        use super::*;
        #[test]
        fn offset() {
            let dim = 8;
            assert_eq!(dim.size(), 8);
            assert_eq!(dim.offset(3), 3);
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim() {
            let dim = 4;
            dim.offset(5);
        }
    }

    mod dim2 {
        use super::*;
        #[test]
        fn offset() {
            let dim = (8, 6);
            assert_eq!(dim.size(), 48);
            assert_eq!(dim.offset((3, 5)), 23);
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim_one() {
            let dim = (8, 6);
            dim.offset((9, 4));
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim_two() {
            let dim = (8, 6);
            dim.offset((7, 8));
        }
    }

    mod dim3 {
        use super::*;
        #[test]
        fn offset() {
            let dim = (2, 6, 6);
            assert_eq!(dim.size(), 72);
            assert_eq!(dim.offset((1, 5, 3)), 69);

            let dim = (1, 2, 3);
            assert_eq!(dim.size(), 6);
            assert_eq!(dim.offset((0, 1, 2)), 5);
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim_one() {
            let dim = (2, 6, 6);
            dim.offset((9, 4, 3));
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim_two() {
            let dim = (2, 6, 6);
            dim.offset((1, 8, 3));
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim_three() {
            let dim = (2, 6, 6);
            dim.offset((1, 4, 12));
        }
    }
}
<commit_msg>Better tests for offset computation<commit_after>use std::ops::Range;

/// A (set of) dimensions in an array. A `Dimensions` object carries informations
/// about its size, and how to convert a multi-dimensional index to a linear
/// index.
pub trait Dimensions: Clone + PartialEq {
    /// The type to use to index this dimension
    type Index: Copy;
    /// Convert an index to a linear offset for this dimension size
    fn offset(&self, index: Self::Index) -> usize;
    /// Get the number of elements in this dimension
    fn size(&self) -> usize;
}

impl Dimensions for usize {
    type Index = usize;

    #[inline(always)]
    fn offset(&self, index: usize) -> usize {
        assert!(index < *self);
        index
    }

    #[inline(always)]
    fn size(&self) -> usize {
        *self
    }
}

impl Dimensions for Range<usize> {
    type Index = usize;

    #[inline(always)]
    fn offset(&self, index: usize) -> usize {
        assert!(self.start <= index && index < self.end);
        index - self.start
    }

    #[inline(always)]
    fn size(&self) -> usize {
        self.end - self.start
    }
}

impl Dimensions for Range<i32> {
    type Index = i32;

    #[inline(always)]
    fn offset(&self, index: i32) -> usize {
        assert!(self.start <= index && index < self.end);
        assert!(index - self.start > 0);
        (index - self.start) as usize
    }

    #[inline(always)]
    fn size(&self) -> usize {
        (self.end - self.start) as usize
    }
}

impl<A, B> Dimensions for (A, B) where A: Dimensions, B: Dimensions {
    type Index = (A::Index, B::Index);

    #[inline(always)]
    fn offset(&self, index: Self::Index) -> usize {
        self.1.size() * self.0.offset(index.0) + self.1.offset(index.1)
    }

    #[inline(always)]
    fn size(&self) -> usize {
        self.0.size() * self.1.size()
    }
}

impl<A, B, C> Dimensions for (A, B, C) where A: Dimensions, B: Dimensions, C: Dimensions {
    type Index = (A::Index, B::Index, C::Index);

    #[inline(always)]
    fn offset(&self, index: Self::Index) -> usize {
        self.2.offset(index.2) + self.2.size() * (self.1.offset(index.1) + self.1.size() * self.0.offset(index.0))
    }

    #[inline(always)]
    fn size(&self) -> usize {
        self.0.size() * self.1.size() * self.2.size()
    }
}

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

    mod urange {
        use super::*;
        #[test]
        fn offset() {
            let dim = 4..10;
            assert_eq!(dim.size(), 6);
            assert_eq!(dim.offset(5), 1);
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim() {
            let dim = 4..10;
            dim.offset(11);
        }

        #[test]
        #[should_panic]
        fn smaller_than_dim() {
            let dim = 4..10;
            dim.offset(2);
        }
    }

    mod irange {
        use super::*;
        #[test]
        fn offset() {
            let dim = -4..10;
            assert_eq!(dim.size(), 14);
            assert_eq!(dim.offset(5), 9);
            assert_eq!(dim.offset(-3), 1);
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim() {
            let dim = -4..10;
            dim.offset(11);
        }

        #[test]
        #[should_panic]
        fn smaller_than_dim() {
            let dim = -4..10;
            dim.offset(-6);
        }
    }

    mod dim1 {
        use super::*;
        #[test]
        fn offset() {
            let dim = 8;
            assert_eq!(dim.size(), 8);
            assert_eq!(dim.offset(3), 3);
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim() {
            let dim = 4;
            dim.offset(5);
        }
    }

    mod dim2 {
        use super::*;
        #[test]
        fn offset() {
            let dim = (2, 3);
            assert_eq!(dim.size(), 6);

            assert_eq!(dim.offset((0, 1)), 1);
            assert_eq!(dim.offset((1, 0)), 3);

            assert_eq!(dim.offset((1, 2)), 5);
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim_one() {
            let dim = (8, 6);
            dim.offset((8, 4));
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim_two() {
            let dim = (8, 6);
            dim.offset((7, 8));
        }
    }

    mod dim3 {
        use super::*;
        #[test]
        fn offset() {
            let dim = (2, 2, 5);
            assert_eq!(dim.size(), 20);

            assert_eq!(dim.offset((0, 0, 1)), 1);
            assert_eq!(dim.offset((0, 1, 0)), 5);
            assert_eq!(dim.offset((1, 0, 0)), 10);

            assert_eq!(dim.offset((1, 1, 4)), 19);
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim_one() {
            let dim = (2, 6, 6);
            dim.offset((9, 4, 3));
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim_two() {
            let dim = (2, 6, 6);
            dim.offset((1, 8, 3));
        }

        #[test]
        #[should_panic]
        fn bigger_than_dim_three() {
            let dim = (2, 6, 6);
            dim.offset((1, 4, 12));
        }
    }
}
<|endoftext|>


<commit_before>//
// Unused import checking
//
// Although this is mostly a lint pass, it lives in here because it depends on
// resolve data structures and because it finalises the privacy information for
// `use` items.
//
// Unused trait imports can't be checked until the method resolution. We save
// candidates here, and do the actual check in librustc_typeck/check_unused.rs.
//
// Checking for unused imports is split into three steps:
//
//  - `UnusedImportCheckVisitor` walks the AST to find all the unused imports
//    inside of `UseTree`s, recording their `NodeId`s and grouping them by
//    the parent `use` item
//
//  - `calc_unused_spans` then walks over all the `use` items marked in the
//    previous step to collect the spans associated with the `NodeId`s and to
//    calculate the spans that can be removed by rustfix; This is done in a
//    separate step to be able to collapse the adjacent spans that rustfix
//    will remove
//
//  - `check_crate` finally emits the diagnostics based on the data generated
//    in the last step

use crate::imports::ImportKind;
use crate::Resolver;

use rustc_ast as ast;
use rustc_ast::node_id::NodeMap;
use rustc_ast::visit::{self, Visitor};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::pluralize;
use rustc_middle::ty;
use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::{MultiSpan, Span, DUMMY_SP};

struct UnusedImport<'a> {
    use_tree: &'a ast::UseTree,
    use_tree_id: ast::NodeId,
    item_span: Span,
    unused: FxHashSet<ast::NodeId>,
}

impl<'a> UnusedImport<'a> {
    fn add(&mut self, id: ast::NodeId) {
        self.unused.insert(id);
    }
}

struct UnusedImportCheckVisitor<'a, 'b> {
    r: &'a mut Resolver<'b>,
    /// All the (so far) unused imports, grouped path list
    unused_imports: NodeMap<UnusedImport<'a>>,
    base_use_tree: Option<&'a ast::UseTree>,
    base_id: ast::NodeId,
    item_span: Span,
}

impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
    // We have information about whether `use` (import) items are actually
    // used now. If an import is not used at all, we signal a lint error.
    fn check_import(&mut self, id: ast::NodeId) {
        let mut used = false;
        self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
        let def_id = self.r.local_def_id(id);
        if !used {
            if self.r.maybe_unused_trait_imports.contains(&def_id) {
                // Check later.
                return;
            }
            self.unused_import(self.base_id).add(id);
        } else {
            // This trait import is definitely used, in a way other than
            // method resolution.
            self.r.maybe_unused_trait_imports.remove(&def_id);
            if let Some(i) = self.unused_imports.get_mut(&self.base_id) {
                i.unused.remove(&id);
            }
        }
    }

    fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport<'a> {
        let use_tree_id = self.base_id;
        let use_tree = self.base_use_tree.unwrap();
        let item_span = self.item_span;

        self.unused_imports.entry(id).or_insert_with(|| UnusedImport {
            use_tree,
            use_tree_id,
            item_span,
            unused: FxHashSet::default(),
        })
    }
}

impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> {
    fn visit_item(&mut self, item: &'a ast::Item) {
        self.item_span = item.span;

        // Ignore is_public import statements because there's no way to be sure
        // whether they're used or not. Also ignore imports with a dummy span
        // because this means that they were generated in some fashion by the
        // compiler and we don't need to consider them.
        if let ast::ItemKind::Use(..) = item.kind {
            if item.vis.kind.is_pub() || item.span.is_dummy() {
                return;
            }
        }

        visit::walk_item(self, item);
    }

    fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId, nested: bool) {
        // Use the base UseTree's NodeId as the item id
        // This allows the grouping of all the lints in the same item
        if !nested {
            self.base_id = id;
            self.base_use_tree = Some(use_tree);
        }

        if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
            if items.is_empty() {
                self.unused_import(self.base_id).add(id);
            }
        } else {
            self.check_import(id);
        }

        visit::walk_use_tree(self, use_tree, id);
    }
}

enum UnusedSpanResult {
    Used,
    FlatUnused(Span, Span),
    NestedFullUnused(Vec<Span>, Span),
    NestedPartialUnused(Vec<Span>, Vec<Span>),
}

fn calc_unused_spans(
    unused_import: &UnusedImport<'_>,
    use_tree: &ast::UseTree,
    use_tree_id: ast::NodeId,
) -> UnusedSpanResult {
    // The full span is the whole item's span if this current tree is not nested inside another
    // This tells rustfix to remove the whole item if all the imports are unused
    let full_span = if unused_import.use_tree.span == use_tree.span {
        unused_import.item_span
    } else {
        use_tree.span
    };
    match use_tree.kind {
        ast::UseTreeKind::Simple(..) | ast::UseTreeKind::Glob => {
            if unused_import.unused.contains(&use_tree_id) {
                UnusedSpanResult::FlatUnused(use_tree.span, full_span)
            } else {
                UnusedSpanResult::Used
            }
        }
        ast::UseTreeKind::Nested(ref nested) => {
            if nested.is_empty() {
                return UnusedSpanResult::FlatUnused(use_tree.span, full_span);
            }

            let mut unused_spans = Vec::new();
            let mut to_remove = Vec::new();
            let mut all_nested_unused = true;
            let mut previous_unused = false;
            for (pos, (use_tree, use_tree_id)) in nested.iter().enumerate() {
                let remove = match calc_unused_spans(unused_import, use_tree, *use_tree_id) {
                    UnusedSpanResult::Used => {
                        all_nested_unused = false;
                        None
                    }
                    UnusedSpanResult::FlatUnused(span, remove) => {
                        unused_spans.push(span);
                        Some(remove)
                    }
                    UnusedSpanResult::NestedFullUnused(mut spans, remove) => {
                        unused_spans.append(&mut spans);
                        Some(remove)
                    }
                    UnusedSpanResult::NestedPartialUnused(mut spans, mut to_remove_extra) => {
                        all_nested_unused = false;
                        unused_spans.append(&mut spans);
                        to_remove.append(&mut to_remove_extra);
                        None
                    }
                };
                if let Some(remove) = remove {
                    let remove_span = if nested.len() == 1 {
                        remove
                    } else if pos == nested.len() - 1 || !all_nested_unused {
                        // Delete everything from the end of the last import, to delete the
                        // previous comma
                        nested[pos - 1].0.span.shrink_to_hi().to(use_tree.span)
                    } else {
                        // Delete everything until the next import, to delete the trailing commas
                        use_tree.span.to(nested[pos + 1].0.span.shrink_to_lo())
                    };

                    // Try to collapse adjacent spans into a single one. This prevents all cases of
                    // overlapping removals, which are not supported by rustfix
                    if previous_unused && !to_remove.is_empty() {
                        let previous = to_remove.pop().unwrap();
                        to_remove.push(previous.to(remove_span));
                    } else {
                        to_remove.push(remove_span);
                    }
                }
                previous_unused = remove.is_some();
            }
            if unused_spans.is_empty() {
                UnusedSpanResult::Used
            } else if all_nested_unused {
                UnusedSpanResult::NestedFullUnused(unused_spans, full_span)
            } else {
                UnusedSpanResult::NestedPartialUnused(unused_spans, to_remove)
            }
        }
    }
}

impl Resolver<'_> {
    crate fn check_unused(&mut self, krate: &ast::Crate) {
        for import in self.potentially_unused_imports.iter() {
            match import.kind {
                _ if import.used.get()
                    || import.vis.get() == ty::Visibility::Public
                    || import.span.is_dummy() =>
                {
                    if let ImportKind::MacroUse = import.kind {
                        if !import.span.is_dummy() {
                            self.lint_buffer.buffer_lint(
                                MACRO_USE_EXTERN_CRATE,
                                import.id,
                                import.span,
                                "deprecated `#[macro_use]` attribute used to \
                                import macros should be replaced at use sites \
                                with a `use` item to import the macro \
                                instead",
                            );
                        }
                    }
                }
                ImportKind::ExternCrate { .. } => {
                    let def_id = self.local_def_id(import.id);
                    self.maybe_unused_extern_crates.push((def_id, import.span));
                }
                ImportKind::MacroUse => {
                    let msg = "unused `#[macro_use]` import";
                    self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
                }
                _ => {}
            }
        }

        let mut visitor = UnusedImportCheckVisitor {
            r: self,
            unused_imports: Default::default(),
            base_use_tree: None,
            base_id: ast::DUMMY_NODE_ID,
            item_span: DUMMY_SP,
        };
        visit::walk_crate(&mut visitor, krate);

        for unused in visitor.unused_imports.values() {
            let mut fixes = Vec::new();
            let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
                UnusedSpanResult::Used => continue,
                UnusedSpanResult::FlatUnused(span, remove) => {
                    fixes.push((remove, String::new()));
                    vec![span]
                }
                UnusedSpanResult::NestedFullUnused(spans, remove) => {
                    fixes.push((remove, String::new()));
                    spans
                }
                UnusedSpanResult::NestedPartialUnused(spans, remove) => {
                    for fix in &remove {
                        fixes.push((*fix, String::new()));
                    }
                    spans
                }
            };

            let len = spans.len();
            spans.sort();
            let ms = MultiSpan::from_spans(spans.clone());
            let mut span_snippets = spans
                .iter()
                .filter_map(|s| match visitor.r.session.source_map().span_to_snippet(*s) {
                    Ok(s) => Some(format!("`{}`", s)),
                    _ => None,
                })
                .collect::<Vec<String>>();
            span_snippets.sort();
            let msg = format!(
                "unused import{}{}",
                pluralize!(len),
                if !span_snippets.is_empty() {
                    format!(": {}", span_snippets.join(", "))
                } else {
                    String::new()
                }
            );

            let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
                "remove the whole `use` item"
            } else if spans.len() > 1 {
                "remove the unused imports"
            } else {
                "remove the unused import"
            };

            visitor.r.lint_buffer.buffer_lint_with_diagnostic(
                UNUSED_IMPORTS,
                unused.use_tree_id,
                ms,
                &msg,
                BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
            );
        }
    }
}
<commit_msg>Include attributes in removal span for unused imports.<commit_after>//
// Unused import checking
//
// Although this is mostly a lint pass, it lives in here because it depends on
// resolve data structures and because it finalises the privacy information for
// `use` items.
//
// Unused trait imports can't be checked until the method resolution. We save
// candidates here, and do the actual check in librustc_typeck/check_unused.rs.
//
// Checking for unused imports is split into three steps:
//
//  - `UnusedImportCheckVisitor` walks the AST to find all the unused imports
//    inside of `UseTree`s, recording their `NodeId`s and grouping them by
//    the parent `use` item
//
//  - `calc_unused_spans` then walks over all the `use` items marked in the
//    previous step to collect the spans associated with the `NodeId`s and to
//    calculate the spans that can be removed by rustfix; This is done in a
//    separate step to be able to collapse the adjacent spans that rustfix
//    will remove
//
//  - `check_crate` finally emits the diagnostics based on the data generated
//    in the last step

use crate::imports::ImportKind;
use crate::Resolver;

use rustc_ast as ast;
use rustc_ast::node_id::NodeMap;
use rustc_ast::visit::{self, Visitor};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::pluralize;
use rustc_middle::ty;
use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::{MultiSpan, Span, DUMMY_SP};

struct UnusedImport<'a> {
    use_tree: &'a ast::UseTree,
    use_tree_id: ast::NodeId,
    item_span: Span,
    unused: FxHashSet<ast::NodeId>,
}

impl<'a> UnusedImport<'a> {
    fn add(&mut self, id: ast::NodeId) {
        self.unused.insert(id);
    }
}

struct UnusedImportCheckVisitor<'a, 'b> {
    r: &'a mut Resolver<'b>,
    /// All the (so far) unused imports, grouped path list
    unused_imports: NodeMap<UnusedImport<'a>>,
    base_use_tree: Option<&'a ast::UseTree>,
    base_id: ast::NodeId,
    item_span: Span,
}

impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
    // We have information about whether `use` (import) items are actually
    // used now. If an import is not used at all, we signal a lint error.
    fn check_import(&mut self, id: ast::NodeId) {
        let mut used = false;
        self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
        let def_id = self.r.local_def_id(id);
        if !used {
            if self.r.maybe_unused_trait_imports.contains(&def_id) {
                // Check later.
                return;
            }
            self.unused_import(self.base_id).add(id);
        } else {
            // This trait import is definitely used, in a way other than
            // method resolution.
            self.r.maybe_unused_trait_imports.remove(&def_id);
            if let Some(i) = self.unused_imports.get_mut(&self.base_id) {
                i.unused.remove(&id);
            }
        }
    }

    fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport<'a> {
        let use_tree_id = self.base_id;
        let use_tree = self.base_use_tree.unwrap();
        let item_span = self.item_span;

        self.unused_imports.entry(id).or_insert_with(|| UnusedImport {
            use_tree,
            use_tree_id,
            item_span,
            unused: FxHashSet::default(),
        })
    }
}

impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> {
    fn visit_item(&mut self, item: &'a ast::Item) {
        self.item_span = item.span_with_attributes();

        // Ignore is_public import statements because there's no way to be sure
        // whether they're used or not. Also ignore imports with a dummy span
        // because this means that they were generated in some fashion by the
        // compiler and we don't need to consider them.
        if let ast::ItemKind::Use(..) = item.kind {
            if item.vis.kind.is_pub() || item.span.is_dummy() {
                return;
            }
        }

        visit::walk_item(self, item);
    }

    fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId, nested: bool) {
        // Use the base UseTree's NodeId as the item id
        // This allows the grouping of all the lints in the same item
        if !nested {
            self.base_id = id;
            self.base_use_tree = Some(use_tree);
        }

        if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
            if items.is_empty() {
                self.unused_import(self.base_id).add(id);
            }
        } else {
            self.check_import(id);
        }

        visit::walk_use_tree(self, use_tree, id);
    }
}

enum UnusedSpanResult {
    Used,
    FlatUnused(Span, Span),
    NestedFullUnused(Vec<Span>, Span),
    NestedPartialUnused(Vec<Span>, Vec<Span>),
}

fn calc_unused_spans(
    unused_import: &UnusedImport<'_>,
    use_tree: &ast::UseTree,
    use_tree_id: ast::NodeId,
) -> UnusedSpanResult {
    // The full span is the whole item's span if this current tree is not nested inside another
    // This tells rustfix to remove the whole item if all the imports are unused
    let full_span = if unused_import.use_tree.span == use_tree.span {
        unused_import.item_span
    } else {
        use_tree.span
    };
    match use_tree.kind {
        ast::UseTreeKind::Simple(..) | ast::UseTreeKind::Glob => {
            if unused_import.unused.contains(&use_tree_id) {
                UnusedSpanResult::FlatUnused(use_tree.span, full_span)
            } else {
                UnusedSpanResult::Used
            }
        }
        ast::UseTreeKind::Nested(ref nested) => {
            if nested.is_empty() {
                return UnusedSpanResult::FlatUnused(use_tree.span, full_span);
            }

            let mut unused_spans = Vec::new();
            let mut to_remove = Vec::new();
            let mut all_nested_unused = true;
            let mut previous_unused = false;
            for (pos, (use_tree, use_tree_id)) in nested.iter().enumerate() {
                let remove = match calc_unused_spans(unused_import, use_tree, *use_tree_id) {
                    UnusedSpanResult::Used => {
                        all_nested_unused = false;
                        None
                    }
                    UnusedSpanResult::FlatUnused(span, remove) => {
                        unused_spans.push(span);
                        Some(remove)
                    }
                    UnusedSpanResult::NestedFullUnused(mut spans, remove) => {
                        unused_spans.append(&mut spans);
                        Some(remove)
                    }
                    UnusedSpanResult::NestedPartialUnused(mut spans, mut to_remove_extra) => {
                        all_nested_unused = false;
                        unused_spans.append(&mut spans);
                        to_remove.append(&mut to_remove_extra);
                        None
                    }
                };
                if let Some(remove) = remove {
                    let remove_span = if nested.len() == 1 {
                        remove
                    } else if pos == nested.len() - 1 || !all_nested_unused {
                        // Delete everything from the end of the last import, to delete the
                        // previous comma
                        nested[pos - 1].0.span.shrink_to_hi().to(use_tree.span)
                    } else {
                        // Delete everything until the next import, to delete the trailing commas
                        use_tree.span.to(nested[pos + 1].0.span.shrink_to_lo())
                    };

                    // Try to collapse adjacent spans into a single one. This prevents all cases of
                    // overlapping removals, which are not supported by rustfix
                    if previous_unused && !to_remove.is_empty() {
                        let previous = to_remove.pop().unwrap();
                        to_remove.push(previous.to(remove_span));
                    } else {
                        to_remove.push(remove_span);
                    }
                }
                previous_unused = remove.is_some();
            }
            if unused_spans.is_empty() {
                UnusedSpanResult::Used
            } else if all_nested_unused {
                UnusedSpanResult::NestedFullUnused(unused_spans, full_span)
            } else {
                UnusedSpanResult::NestedPartialUnused(unused_spans, to_remove)
            }
        }
    }
}

impl Resolver<'_> {
    crate fn check_unused(&mut self, krate: &ast::Crate) {
        for import in self.potentially_unused_imports.iter() {
            match import.kind {
                _ if import.used.get()
                    || import.vis.get() == ty::Visibility::Public
                    || import.span.is_dummy() =>
                {
                    if let ImportKind::MacroUse = import.kind {
                        if !import.span.is_dummy() {
                            self.lint_buffer.buffer_lint(
                                MACRO_USE_EXTERN_CRATE,
                                import.id,
                                import.span,
                                "deprecated `#[macro_use]` attribute used to \
                                import macros should be replaced at use sites \
                                with a `use` item to import the macro \
                                instead",
                            );
                        }
                    }
                }
                ImportKind::ExternCrate { .. } => {
                    let def_id = self.local_def_id(import.id);
                    self.maybe_unused_extern_crates.push((def_id, import.span));
                }
                ImportKind::MacroUse => {
                    let msg = "unused `#[macro_use]` import";
                    self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
                }
                _ => {}
            }
        }

        let mut visitor = UnusedImportCheckVisitor {
            r: self,
            unused_imports: Default::default(),
            base_use_tree: None,
            base_id: ast::DUMMY_NODE_ID,
            item_span: DUMMY_SP,
        };
        visit::walk_crate(&mut visitor, krate);

        for unused in visitor.unused_imports.values() {
            let mut fixes = Vec::new();
            let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
                UnusedSpanResult::Used => continue,
                UnusedSpanResult::FlatUnused(span, remove) => {
                    fixes.push((remove, String::new()));
                    vec![span]
                }
                UnusedSpanResult::NestedFullUnused(spans, remove) => {
                    fixes.push((remove, String::new()));
                    spans
                }
                UnusedSpanResult::NestedPartialUnused(spans, remove) => {
                    for fix in &remove {
                        fixes.push((*fix, String::new()));
                    }
                    spans
                }
            };

            let len = spans.len();
            spans.sort();
            let ms = MultiSpan::from_spans(spans.clone());
            let mut span_snippets = spans
                .iter()
                .filter_map(|s| match visitor.r.session.source_map().span_to_snippet(*s) {
                    Ok(s) => Some(format!("`{}`", s)),
                    _ => None,
                })
                .collect::<Vec<String>>();
            span_snippets.sort();
            let msg = format!(
                "unused import{}{}",
                pluralize!(len),
                if !span_snippets.is_empty() {
                    format!(": {}", span_snippets.join(", "))
                } else {
                    String::new()
                }
            );

            let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
                "remove the whole `use` item"
            } else if spans.len() > 1 {
                "remove the unused imports"
            } else {
                "remove the unused import"
            };

            visitor.r.lint_buffer.buffer_lint_with_diagnostic(
                UNUSED_IMPORTS,
                unused.use_tree_id,
                ms,
                &msg,
                BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
            );
        }
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::fs::File;
use std::io::{self, BufRead};
use std::str::FromStr;

#[macro_use]
extern crate lazy_static;
extern crate if_chain;

struct State<T>(Box<dyn Iterator<Item = T>>, Option<T>);
pub struct Merge<T> {
    count: usize,
    states: Vec<State<T>>,
}

impl<T: 'static + FromStr> Merge<T> {
    pub fn new(filename: &str) -> Self {
        let count = get_number(filename).unwrap();
        let states = (0..count).map(|i| {
            let collection = Box::new(get_collection(filename, i).unwrap());
            State(collection, None)
        }).collect();
        Merge {
            count: count,
            states: states,
        }
    }
}

impl<T: 'static + PartialOrd> Iterator for Merge<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        let count = self.count;
        let states = &mut self.states;
        for i in 0..count {
            let state = &mut states[i];
            if state.1.is_none() {
                state.1 = state.0.next();
            }
        }
        let mut min_index: Option<usize> = None;
        for i in 0..count {
            if_chain::if_chain! {
                if let Some(_) = states[i].1.as_ref();
                if min_index.is_none();
                then {
                    min_index.replace(i);
                }
            }
            if_chain::if_chain! {
                if let Some(val) = states[i].1.as_ref();
                if let Some(m) = min_index;
                if let Some(min) = states[m].1.as_ref();
                if val < min;
                then {
                    min_index.replace(i);
                }
            }
        }
        if let Some(m) = min_index {
            return states[m].1.take();
        }
        return None;
    }
}

pub fn get_number(filename: &str) -> io::Result<usize> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let mut matches = match_lines(filename, &*RE)?;
    return Ok(matches.next().unwrap().parse().unwrap());
}

pub fn get_output<T: FromStr>(filename: &str) -> io::Result<impl Iterator<Item = T>> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"OUTPUT:(.*)").unwrap();
    }
    get_numbers(filename, &*RE)
}

pub fn get_collection<T: FromStr>(filename: &str, idx: usize) -> io::Result<impl Iterator<Item = T>> {
    let regex: Regex = {
        let r = format!("COLLECTION{}:(.*)", idx);
        Regex::new(&r).unwrap()
    };
    get_numbers(filename, &regex)
}

fn get_numbers<T: FromStr>(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = T>> {
    let matches = match_lines(filename, regex)?;
    let to_int = |v: &str| -> Option<T> {
        if let Ok(i) = v.parse::<T>() {
            Some(i)
        } else {
            None
        }
    };
    let values = matches
        .map(move |s| {
            let numbers = s.split(',').filter_map(|v| to_int(&v));
            numbers.collect::<Vec<_>>()
        })
        .flatten();
    Ok(values)
}

fn match_lines(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = String>> {
    let read_lines = move || -> io::Result<_> {
        let file = File::open(filename)?;
        Ok(io::BufReader::new(file).lines().map(|line| line.unwrap()))
    };
    let lines = read_lines()?;
    let r = regex.clone(); // TODO
    let matches =
        lines.filter_map(move |line| r.captures(&line).map(|captures| captures[1].to_string()));
    Ok(matches)
}

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

    #[test]
    fn test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap(), 3);
    }

    #[test]
    fn test_output() {
        let output = [1, 1, 2, 2, 3, 4, 4, 6, 7, 9, 9, 20, 21];
        assert_eq!(
            get_output("../data/test.txt").unwrap().collect::<Vec<u32>>(),
            output
        );
    }

    #[test]
    fn test_collection() {
        let output = [2, 4, 6, 9, 20];
        assert_eq!(
            get_collection("../data/test.txt", 1)
                .unwrap()
                .collect::<Vec<u32>>(),
            output
        );
    }

    fn merge<T: 'static + FromStr + PartialOrd>(filename: &str) -> (impl Iterator<Item = T>, impl Iterator<Item = T>) {
        let result = Merge::new(filename);
        let output = get_output(filename).unwrap();
        (result, output)
    }

    fn assert_iterator<T: PartialEq>(
        iter1: &mut impl Iterator<Item = T>,
        iter2: &mut impl Iterator<Item = T>,
    ) -> bool {
        loop {
            match (iter1.next(), iter2.next()) {
                (None, None) => return true,
                (Some(v1), Some(v2)) if v1 == v2 => continue,
                _ => return false,
            }
        }
    }

    #[test]
    fn test_merge() {
        let filename = "../data/test.txt";
        let (mut result, mut output) = merge::<u32>(filename);
        assert!(assert_iterator(&mut result, &mut output));
    }

    #[test]
    #[should_panic]
    fn test_bad_merge() {
        let filename = "../data/bad.txt";
        let (_result, _output) = merge::<u32>(filename);
    }

    #[test]
    fn test_zero_merge() {
        let filename = "../data/zero.txt";
        let (mut result, mut output) = merge::<u32>(filename);
        assert!(result.next().is_none());
        assert!(output.next().is_none());
    }

    #[test]
    fn test_err() {
        let filename = "../data/err.txt";
        let (mut result, mut output) = merge::<u32>(filename);
        assert!(!assert_iterator(&mut result, &mut output));
    }
}
<commit_msg>Removed one of the lifetimes<commit_after>use regex::Regex;
use std::fs::File;
use std::io::{self, BufRead};
use std::str::FromStr;

#[macro_use]
extern crate lazy_static;
extern crate if_chain;

struct State<T>(Box<dyn Iterator<Item = T>>, Option<T>);
pub struct Merge<T> {
    count: usize,
    states: Vec<State<T>>,
}

impl<T: 'static + FromStr> Merge<T> {
    pub fn new(filename: &str) -> Self {
        let count = get_number(filename).unwrap();
        let states = (0..count).map(|i| {
            let collection = Box::new(get_collection(filename, i).unwrap());
            State(collection, None)
        }).collect();
        Merge {
            count: count,
            states: states,
        }
    }
}

impl<T: PartialOrd> Iterator for Merge<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        let count = self.count;
        let states = &mut self.states;
        for i in 0..count {
            let state = &mut states[i];
            if state.1.is_none() {
                state.1 = state.0.next();
            }
        }
        let mut min_index: Option<usize> = None;
        for i in 0..count {
            if_chain::if_chain! {
                if let Some(_) = states[i].1.as_ref();
                if min_index.is_none();
                then {
                    min_index.replace(i);
                }
            }
            if_chain::if_chain! {
                if let Some(val) = states[i].1.as_ref();
                if let Some(m) = min_index;
                if let Some(min) = states[m].1.as_ref();
                if val < min;
                then {
                    min_index.replace(i);
                }
            }
        }
        if let Some(m) = min_index {
            return states[m].1.take();
        }
        return None;
    }
}

pub fn get_number(filename: &str) -> io::Result<usize> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let mut matches = match_lines(filename, &*RE)?;
    return Ok(matches.next().unwrap().parse().unwrap());
}

pub fn get_output<T: FromStr>(filename: &str) -> io::Result<impl Iterator<Item = T>> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"OUTPUT:(.*)").unwrap();
    }
    get_numbers(filename, &*RE)
}

pub fn get_collection<T: FromStr>(filename: &str, idx: usize) -> io::Result<impl Iterator<Item = T>> {
    let regex: Regex = {
        let r = format!("COLLECTION{}:(.*)", idx);
        Regex::new(&r).unwrap()
    };
    get_numbers(filename, &regex)
}

fn get_numbers<T: FromStr>(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = T>> {
    let matches = match_lines(filename, regex)?;
    let to_int = |v: &str| -> Option<T> {
        if let Ok(i) = v.parse::<T>() {
            Some(i)
        } else {
            None
        }
    };
    let values = matches
        .map(move |s| {
            let numbers = s.split(',').filter_map(|v| to_int(&v));
            numbers.collect::<Vec<_>>()
        })
        .flatten();
    Ok(values)
}

fn match_lines(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = String>> {
    let read_lines = move || -> io::Result<_> {
        let file = File::open(filename)?;
        Ok(io::BufReader::new(file).lines().map(|line| line.unwrap()))
    };
    let lines = read_lines()?;
    let r = regex.clone(); // TODO
    let matches =
        lines.filter_map(move |line| r.captures(&line).map(|captures| captures[1].to_string()));
    Ok(matches)
}

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

    #[test]
    fn test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap(), 3);
    }

    #[test]
    fn test_output() {
        let output = [1, 1, 2, 2, 3, 4, 4, 6, 7, 9, 9, 20, 21];
        assert_eq!(
            get_output("../data/test.txt").unwrap().collect::<Vec<u32>>(),
            output
        );
    }

    #[test]
    fn test_collection() {
        let output = [2, 4, 6, 9, 20];
        assert_eq!(
            get_collection("../data/test.txt", 1)
                .unwrap()
                .collect::<Vec<u32>>(),
            output
        );
    }

    fn merge<T: 'static + FromStr + PartialOrd>(filename: &str) -> (impl Iterator<Item = T>, impl Iterator<Item = T>) {
        let result = Merge::new(filename);
        let output = get_output(filename).unwrap();
        (result, output)
    }

    fn assert_iterator<T: PartialEq>(
        iter1: &mut impl Iterator<Item = T>,
        iter2: &mut impl Iterator<Item = T>,
    ) -> bool {
        loop {
            match (iter1.next(), iter2.next()) {
                (None, None) => return true,
                (Some(v1), Some(v2)) if v1 == v2 => continue,
                _ => return false,
            }
        }
    }

    #[test]
    fn test_merge() {
        let filename = "../data/test.txt";
        let (mut result, mut output) = merge::<u32>(filename);
        assert!(assert_iterator(&mut result, &mut output));
    }

    #[test]
    #[should_panic]
    fn test_bad_merge() {
        let filename = "../data/bad.txt";
        let (_result, _output) = merge::<u32>(filename);
    }

    #[test]
    fn test_zero_merge() {
        let filename = "../data/zero.txt";
        let (mut result, mut output) = merge::<u32>(filename);
        assert!(result.next().is_none());
        assert!(output.next().is_none());
    }

    #[test]
    fn test_err() {
        let filename = "../data/err.txt";
        let (mut result, mut output) = merge::<u32>(filename);
        assert!(!assert_iterator(&mut result, &mut output));
    }
}
<|endoftext|>


<commit_before>use crate::{documents::DOCUMENTS, patches::Patch, sessions::SESSIONS};
use defaults::Defaults;
use eyre::{bail, Result};
use serde::{Deserialize, Serialize};
use serde_json::json;
use serde_with::skip_serializing_none;
use std::collections::HashMap;
use strum::{Display, EnumString, EnumVariantNames};

#[derive(Debug, Display, EnumString, EnumVariantNames, PartialEq)]
#[strum(serialize_all = "lowercase")]
pub enum Protocol {
    #[cfg(any(feature = "request-stdio", feature = "serve-stdio"))]
    Stdio,
    #[cfg(any(feature = "request-http", feature = "serve-http"))]
    Http,
    #[cfg(any(feature = "request-ws", feature = "serve-ws"))]
    Ws,
}

type Params = HashMap<String, serde_json::Value>;

/// A JSON-RPC 2.0 request
///
/// See <https://www.jsonrpc.org/specification#request_object>.
#[skip_serializing_none]
#[derive(Debug, Clone, Defaults, Serialize, Deserialize)]
pub struct Request {
    /// A string specifying the version of the JSON-RPC protocol.
    #[def = "Some(\"2.0\".to_string())"]
    pub jsonrpc: Option<String>,

    /// An identifier for the request established by the client
    /// The standard allows this to be a number or a string but here we use
    /// `u64` because it proved to require less code and is probably more efficient.
    /// May be `None` for notifications or for requests over TTP (where there is not
    /// a need to correlate the request with the response message).
    pub id: Option<u64>,

    /// The method being called
    pub method: String,

    /// Parameters of the method
    pub params: Params,
}

impl Request {
    pub fn new(method: &str, params: Params) -> Self {
        Request {
            method: method.to_string(),
            params,
            ..Default::default()
        }
    }

    pub async fn dispatch(self, client: &str) -> (Response, Subscription) {
        let result: Result<(serde_json::Value, Subscription)> = match self.method.as_str() {
            "sessions.start" => sessions_start(&self.params).await,
            "sessions.stop" => sessions_stop(&self.params).await,
            "sessions.subscribe" => sessions_subscribe(&self.params, client).await,
            "sessions.unsubscribe" => sessions_unsubscribe(&self.params, client).await,
            "documents.open" => documents_open(&self.params).await,
            "documents.close" => documents_close(&self.params).await,
            "documents.patch" => documents_patch(&self.params).await,
            "documents.execute" => documents_execute(&self.params).await,
            "documents.subscribe" => documents_subscribe(&self.params, client).await,
            "documents.unsubscribe" => documents_unsubscribe(&self.params, client).await,
            _ => {
                let error = Error::method_not_found_error(&self.method);
                return (
                    Response::new(self.id, None, Some(error)),
                    Subscription::None,
                );
            }
        };
        match result {
            Ok((value, subscription)) => (Response::new(self.id, Some(value), None), subscription),
            Err(error) => {
                // If the error is JSON-RPC error from this module, just return that.
                // Otherwise, convert it into a generic `server_error`.
                let message = error.to_string();
                let error = match error.downcast::<Error>() {
                    Ok(error) => error,
                    Err(_) => Error::server_error(&message),
                };
                (
                    Response::new(self.id, None, Some(error)),
                    Subscription::None,
                )
            }
        }
    }
}

/// A JSON-RPC 2.0 notification
///
/// A `Notification` is just a `Request` with `id: None`.
///
/// See <https://www.jsonrpc.org/specification#notification>.
pub type Notification = Request;

/// A JSON-RPC 2.0 response
///
/// See <https://www.jsonrpc.org/specification#response_object>.
#[skip_serializing_none]
#[derive(Debug, Defaults, PartialEq, Serialize, Deserialize)]
pub struct Response {
    /// A string specifying the version of the JSON-RPC protocol.
    #[def = "Some(\"2.0\".to_string())"]
    pub jsonrpc: Option<String>,

    /// The id of the request that this response is for
    pub id: Option<u64>,

    /// The result of the method call
    pub result: Option<serde_json::Value>,

    /// Any error that may have occurred
    pub error: Option<Error>,
}

impl Response {
    pub fn new(id: Option<u64>, result: Option<serde_json::Value>, error: Option<Error>) -> Self {
        Response {
            id,
            result,
            error,
            ..Default::default()
        }
    }
}

pub enum Subscription {
    None,
    Subscribe(String),
    Unsubscribe(String),
}

/// A JSON-RPC 2.0 error
///
/// See <https://www.jsonrpc.org/specification#error_object>.
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Error {
    /// A number that indicates the error type that ocurred
    pub code: i16,

    /// A string providing a short description of the error
    pub message: String,

    /// A value that contains additional information about the error
    pub data: Option<serde_json::Value>,
}

// Implement necessary traits to treat JSON-RPC errors as Rust errors
// so they can be part of a `Result`.

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "JSON-RPC Error: {} ({})", self.message, self.code)
    }
}

impl std::error::Error for Error {}

impl Error {
    /// Create an error
    pub fn new(code: i16, message: &str, data: Option<serde_json::Value>) -> Self {
        Self {
            code,
            message: message.to_string(),
            data,
        }
    }

    /// A parse error
    pub fn parse_error(details: &str) -> Self {
        Self {
            code: -32700,
            message: format!("Error while parsing request: {}", details),
            data: Some(serde_json::json!({ "details": details })),
        }
    }

    /// An error when a client sends an invalid request
    pub fn invalid_request_error(message: &str) -> Self {
        Self {
            code: -32600,
            message: format!("Request is invalid: {}", message),
            data: None,
        }
    }

    /// An error when the requested method does not exist
    pub fn method_not_found_error(method: &str) -> Self {
        Self {
            code: -32601,
            message: format!("Method '{}' does not exist", method),
            data: None,
        }
    }

    /// An error when one of more parameters are invalid
    pub fn invalid_param_error(message: &str) -> Self {
        Self {
            code: -32602,
            message: message.to_string(),
            data: None,
        }
    }

    /// A generic internal server error
    pub fn server_error(message: &str) -> Self {
        Self {
            code: -32000,
            message: message.to_string(),
            data: None,
        }
    }

    /// An error to indicate the server lacks the requested capability
    pub fn capability_error(capability: &str, method: &str, params: &serde_json::Value) -> Self {
        Self {
            code: -32001,
            message: format!("Incapable of {}", capability),
            data: Some(serde_json::json!({
                "method": method,
                "params": params
            })),
        }
    }
}

// The following are dispatching functions that check the supplied JSON arguments
// and send them on to the relevant core functions, raising errors is arguments are
// missing or of the wrong type, and converting returned values to JSON.

async fn sessions_start(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let project = required_string(params, "projectId")?;
    let snapshot = required_string(params, "snapshotId")?;

    let session = SESSIONS.start(&project, &snapshot).await?;
    Ok((json!(session), Subscription::None))
}

async fn sessions_stop(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "sessionId")?;

    let session = SESSIONS.stop(&id).await?;
    Ok((json!(session), Subscription::None))
}

async fn sessions_subscribe(
    params: &Params,
    client: &str,
) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "sessionId")?;
    let topic = required_string(params, "topic")?;

    let (session, topic) = SESSIONS.subscribe(&id, &topic, client).await?;
    Ok((json!(session), Subscription::Subscribe(topic)))
}

async fn sessions_unsubscribe(
    params: &Params,
    client: &str,
) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "sessionId")?;
    let topic = required_string(params, "topic")?;

    let (session, topic) = SESSIONS.unsubscribe(&id, &topic, client).await?;
    Ok((json!(session), Subscription::Unsubscribe(topic)))
}

async fn documents_open(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let path = required_string(params, "path")?;

    let document = DOCUMENTS.open(&path, None).await?;
    Ok((json!(document), Subscription::None))
}

async fn documents_close(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "documentId")?;

    let document = DOCUMENTS.close(&id).await?;
    Ok((json!(document), Subscription::None))
}

async fn documents_subscribe(
    params: &Params,
    client: &str,
) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "documentId")?;
    let topic = required_string(params, "topic")?;

    let (document, topic) = DOCUMENTS.subscribe(&id, &topic, client).await?;
    Ok((json!(document), Subscription::Subscribe(topic)))
}

async fn documents_unsubscribe(
    params: &Params,
    client: &str,
) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "documentId")?;
    let topic = required_string(params, "topic")?;

    let (document, topic) = DOCUMENTS.unsubscribe(&id, &topic, client).await?;
    Ok((json!(document), Subscription::Unsubscribe(topic)))
}

async fn documents_patch(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "documentId")?;
    let node_id = required_string(params, "nodeId")?;
    let patch = required_value(params, "patch")?;
    let patch: Patch = serde_json::from_value(patch)?;

    let document = DOCUMENTS.patch(&id, &node_id, patch).await?;
    Ok((json!(document), Subscription::None))
}

async fn documents_execute(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "documentId")?;
    let node_id = required_string(params, "nodeId")?;
    let patch = match optional_value(params, "patch") {
        Some(patch) => serde_json::from_value(patch)?,
        None => None,
    };

    let document = DOCUMENTS.execute(&id, &node_id, patch).await?;
    Ok((json!(document), Subscription::None))
}

// Helper functions for getting JSON-RPC parameters and raising appropriate errors
// if they are not present or of wrong type

fn required_value(params: &Params, name: &str) -> Result<serde_json::Value> {
    if let Some(param) = params.get(name) {
        Ok(param.clone())
    } else {
        bail!(Error::invalid_param_error(&format!(
            "Parameter `{}` is required",
            name
        )))
    }
}

fn optional_value(params: &Params, name: &str) -> Option<serde_json::Value> {
    params.get(name).cloned()
}

fn required_string(params: &Params, name: &str) -> Result<String> {
    if let Some(param) = required_value(params, name)?.as_str() {
        Ok(param.to_string())
    } else {
        bail!(Error::invalid_param_error(&format!(
            "Parameter `{}` is expected to be a string",
            name
        )))
    }
}
<commit_msg>fix(Server): Log errors on the server<commit_after>use crate::{documents::DOCUMENTS, patches::Patch, sessions::SESSIONS};
use defaults::Defaults;
use eyre::{bail, Result};
use serde::{Deserialize, Serialize};
use serde_json::json;
use serde_with::skip_serializing_none;
use std::collections::HashMap;
use strum::{Display, EnumString, EnumVariantNames};

#[derive(Debug, Display, EnumString, EnumVariantNames, PartialEq)]
#[strum(serialize_all = "lowercase")]
pub enum Protocol {
    #[cfg(any(feature = "request-stdio", feature = "serve-stdio"))]
    Stdio,
    #[cfg(any(feature = "request-http", feature = "serve-http"))]
    Http,
    #[cfg(any(feature = "request-ws", feature = "serve-ws"))]
    Ws,
}

type Params = HashMap<String, serde_json::Value>;

/// A JSON-RPC 2.0 request
///
/// See <https://www.jsonrpc.org/specification#request_object>.
#[skip_serializing_none]
#[derive(Debug, Clone, Defaults, Serialize, Deserialize)]
pub struct Request {
    /// A string specifying the version of the JSON-RPC protocol.
    #[def = "Some(\"2.0\".to_string())"]
    pub jsonrpc: Option<String>,

    /// An identifier for the request established by the client
    /// The standard allows this to be a number or a string but here we use
    /// `u64` because it proved to require less code and is probably more efficient.
    /// May be `None` for notifications or for requests over TTP (where there is not
    /// a need to correlate the request with the response message).
    pub id: Option<u64>,

    /// The method being called
    pub method: String,

    /// Parameters of the method
    pub params: Params,
}

impl Request {
    pub fn new(method: &str, params: Params) -> Self {
        Request {
            method: method.to_string(),
            params,
            ..Default::default()
        }
    }

    pub async fn dispatch(self, client: &str) -> (Response, Subscription) {
        let result: Result<(serde_json::Value, Subscription)> = match self.method.as_str() {
            "sessions.start" => sessions_start(&self.params).await,
            "sessions.stop" => sessions_stop(&self.params).await,
            "sessions.subscribe" => sessions_subscribe(&self.params, client).await,
            "sessions.unsubscribe" => sessions_unsubscribe(&self.params, client).await,
            "documents.open" => documents_open(&self.params).await,
            "documents.close" => documents_close(&self.params).await,
            "documents.patch" => documents_patch(&self.params).await,
            "documents.execute" => documents_execute(&self.params).await,
            "documents.subscribe" => documents_subscribe(&self.params, client).await,
            "documents.unsubscribe" => documents_unsubscribe(&self.params, client).await,
            _ => {
                let error = Error::method_not_found_error(&self.method);
                return (
                    Response::new(self.id, None, Some(error)),
                    Subscription::None,
                );
            }
        };
        match result {
            Ok((value, subscription)) => (Response::new(self.id, Some(value), None), subscription),
            Err(error) => {
                // If the error is JSON-RPC error from this module, just return that.
                // Otherwise, convert it into a generic `server_error` and log it.
                let message = error.to_string();
                let error = match error.downcast::<Error>() {
                    Ok(error) => error,
                    Err(_) => {
                        tracing::error!("{}", message);
                        Error::server_error(&message)
                    }
                };
                (
                    Response::new(self.id, None, Some(error)),
                    Subscription::None,
                )
            }
        }
    }
}

/// A JSON-RPC 2.0 notification
///
/// A `Notification` is just a `Request` with `id: None`.
///
/// See <https://www.jsonrpc.org/specification#notification>.
pub type Notification = Request;

/// A JSON-RPC 2.0 response
///
/// See <https://www.jsonrpc.org/specification#response_object>.
#[skip_serializing_none]
#[derive(Debug, Defaults, PartialEq, Serialize, Deserialize)]
pub struct Response {
    /// A string specifying the version of the JSON-RPC protocol.
    #[def = "Some(\"2.0\".to_string())"]
    pub jsonrpc: Option<String>,

    /// The id of the request that this response is for
    pub id: Option<u64>,

    /// The result of the method call
    pub result: Option<serde_json::Value>,

    /// Any error that may have occurred
    pub error: Option<Error>,
}

impl Response {
    pub fn new(id: Option<u64>, result: Option<serde_json::Value>, error: Option<Error>) -> Self {
        Response {
            id,
            result,
            error,
            ..Default::default()
        }
    }
}

pub enum Subscription {
    None,
    Subscribe(String),
    Unsubscribe(String),
}

/// A JSON-RPC 2.0 error
///
/// See <https://www.jsonrpc.org/specification#error_object>.
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Error {
    /// A number that indicates the error type that ocurred
    pub code: i16,

    /// A string providing a short description of the error
    pub message: String,

    /// A value that contains additional information about the error
    pub data: Option<serde_json::Value>,
}

// Implement necessary traits to treat JSON-RPC errors as Rust errors
// so they can be part of a `Result`.

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "JSON-RPC Error: {} ({})", self.message, self.code)
    }
}

impl std::error::Error for Error {}

impl Error {
    /// Create an error
    pub fn new(code: i16, message: &str, data: Option<serde_json::Value>) -> Self {
        Self {
            code,
            message: message.to_string(),
            data,
        }
    }

    /// A parse error
    pub fn parse_error(details: &str) -> Self {
        Self {
            code: -32700,
            message: format!("Error while parsing request: {}", details),
            data: Some(serde_json::json!({ "details": details })),
        }
    }

    /// An error when a client sends an invalid request
    pub fn invalid_request_error(message: &str) -> Self {
        Self {
            code: -32600,
            message: format!("Request is invalid: {}", message),
            data: None,
        }
    }

    /// An error when the requested method does not exist
    pub fn method_not_found_error(method: &str) -> Self {
        Self {
            code: -32601,
            message: format!("Method '{}' does not exist", method),
            data: None,
        }
    }

    /// An error when one of more parameters are invalid
    pub fn invalid_param_error(message: &str) -> Self {
        Self {
            code: -32602,
            message: message.to_string(),
            data: None,
        }
    }

    /// A generic internal server error
    pub fn server_error(message: &str) -> Self {
        Self {
            code: -32000,
            message: message.to_string(),
            data: None,
        }
    }

    /// An error to indicate the server lacks the requested capability
    pub fn capability_error(capability: &str, method: &str, params: &serde_json::Value) -> Self {
        Self {
            code: -32001,
            message: format!("Incapable of {}", capability),
            data: Some(serde_json::json!({
                "method": method,
                "params": params
            })),
        }
    }
}

// The following are dispatching functions that check the supplied JSON arguments
// and send them on to the relevant core functions, raising errors is arguments are
// missing or of the wrong type, and converting returned values to JSON.

async fn sessions_start(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let project = required_string(params, "projectId")?;
    let snapshot = required_string(params, "snapshotId")?;

    let session = SESSIONS.start(&project, &snapshot).await?;
    Ok((json!(session), Subscription::None))
}

async fn sessions_stop(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "sessionId")?;

    let session = SESSIONS.stop(&id).await?;
    Ok((json!(session), Subscription::None))
}

async fn sessions_subscribe(
    params: &Params,
    client: &str,
) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "sessionId")?;
    let topic = required_string(params, "topic")?;

    let (session, topic) = SESSIONS.subscribe(&id, &topic, client).await?;
    Ok((json!(session), Subscription::Subscribe(topic)))
}

async fn sessions_unsubscribe(
    params: &Params,
    client: &str,
) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "sessionId")?;
    let topic = required_string(params, "topic")?;

    let (session, topic) = SESSIONS.unsubscribe(&id, &topic, client).await?;
    Ok((json!(session), Subscription::Unsubscribe(topic)))
}

async fn documents_open(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let path = required_string(params, "path")?;

    let document = DOCUMENTS.open(&path, None).await?;
    Ok((json!(document), Subscription::None))
}

async fn documents_close(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "documentId")?;

    let document = DOCUMENTS.close(&id).await?;
    Ok((json!(document), Subscription::None))
}

async fn documents_subscribe(
    params: &Params,
    client: &str,
) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "documentId")?;
    let topic = required_string(params, "topic")?;

    let (document, topic) = DOCUMENTS.subscribe(&id, &topic, client).await?;
    Ok((json!(document), Subscription::Subscribe(topic)))
}

async fn documents_unsubscribe(
    params: &Params,
    client: &str,
) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "documentId")?;
    let topic = required_string(params, "topic")?;

    let (document, topic) = DOCUMENTS.unsubscribe(&id, &topic, client).await?;
    Ok((json!(document), Subscription::Unsubscribe(topic)))
}

async fn documents_patch(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "documentId")?;
    let node_id = required_string(params, "nodeId")?;
    let patch = required_value(params, "patch")?;
    let patch: Patch = serde_json::from_value(patch)?;

    let document = DOCUMENTS.patch(&id, &node_id, patch).await?;
    Ok((json!(document), Subscription::None))
}

async fn documents_execute(params: &Params) -> Result<(serde_json::Value, Subscription)> {
    let id = required_string(params, "documentId")?;
    let node_id = required_string(params, "nodeId")?;
    let patch = match optional_value(params, "patch") {
        Some(patch) => serde_json::from_value(patch)?,
        None => None,
    };

    let document = DOCUMENTS.execute(&id, &node_id, patch).await?;
    Ok((json!(document), Subscription::None))
}

// Helper functions for getting JSON-RPC parameters and raising appropriate errors
// if they are not present or of wrong type

fn required_value(params: &Params, name: &str) -> Result<serde_json::Value> {
    if let Some(param) = params.get(name) {
        Ok(param.clone())
    } else {
        bail!(Error::invalid_param_error(&format!(
            "Parameter `{}` is required",
            name
        )))
    }
}

fn optional_value(params: &Params, name: &str) -> Option<serde_json::Value> {
    params.get(name).cloned()
}

fn required_string(params: &Params, name: &str) -> Result<String> {
    if let Some(param) = required_value(params, name)?.as_str() {
        Ok(param.to_string())
    } else {
        bail!(Error::invalid_param_error(&format!(
            "Parameter `{}` is expected to be a string",
            name
        )))
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::sync::Arc;
use rand::{Rng, XorShiftRng, SeedableRng};
use quickcheck;
use quickcheck::TestResult;
use player::Player;
use zobrist::Zobrist;
use field;
use field::{Pos, Field};

fn construct_field(image: &str) -> Field {
  let lines = image.split('\n').map(|line| line.trim_matches(' ')).filter(|line| !line.is_empty()).collect::<Vec<&str>>();
  let height = lines.len() as u32;
  assert!(height > 0);
  let width = lines.first().unwrap().len() as u32;
  assert!(lines.iter().all(|line| line.len() as u32 == width));
  let mut moves = lines.into_iter().enumerate().flat_map(|(y, line)|
    line.chars().enumerate().filter(|&(_, c)| c.to_ascii_lowercase() != c.to_ascii_uppercase()).map(move |(x, c)| (c, x as u32, y as u32))
  ).collect::<Vec<(char, u32, u32)>>();
  moves.sort_by(|&(c1, _, _), &(c2, _, _)| (c1.to_ascii_lowercase(), c1.is_lowercase()).cmp(&(c2.to_ascii_lowercase(), c2.is_lowercase())));
  let mut rng = XorShiftRng::new_unseeded();
  let zobrist = Arc::new(Zobrist::new(field::length(width, height) * 2, &mut rng));
  let mut field = Field::new(width, height, zobrist);
  for (c, x, y) in moves.into_iter() {
    let player = Player::from_bool(c.is_uppercase());
    let pos = field.to_pos(x, y);
    field.put_point(pos, player);
  }
  field
}

#[test]
fn simple_surround() {
  let field = construct_field(
    "
    .a.
    cBa
    .a.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(!field.cell(field.to_pos(1, 1)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(0, 1)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 0)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 2)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(2, 1)).is_putting_allowed());
}

#[test]
fn surround_empty_territory() {
  let field = construct_field(
    "
    .a.
    a.a
    .a.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 0);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(field.cell(field.to_pos(1, 1)).is_putting_allowed());
  assert!(field.cell(field.to_pos(1, 1)).is_empty_base());
  assert_eq!(field.cell(field.to_pos(1, 1)).get_empty_base_player(), Some(Player::Red));
  assert!(!field.cell(field.to_pos(0, 1)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 0)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 2)).is_putting_allowed());
  assert!(!field.is_putting_allowed(field.to_pos(2, 1)));
}

#[test]
fn move_priority() {
  let field = construct_field(
    "
    .aB.
    aCaB
    .aB.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 0);
  assert_eq!(field.captured_count(Player::Black), 1);
}

#[test]
fn move_priority_big() {
  let field = construct_field(
    "
    .B..
    BaB.
    aCaB
    .aB.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 0);
  assert_eq!(field.captured_count(Player::Black), 2);
}

#[test]
fn onion_surroundings() {
  let field = construct_field(
    "
    ...c...
    ..cBc..
    .cBaBc.
    ..cBc..
    ...c...
    "
  );
  assert_eq!(field.captured_count(Player::Red), 4);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn apply_control_surrounding_in_same_turn() {
  let field = construct_field(
    "
    .a.
    aBa
    .a.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn double_surround() {
  let field = construct_field(
    "
    .b.b..
    bAzAb.
    .b.b..
    "
  );
  assert_eq!(field.captured_count(Player::Red), 2);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn double_surround_with_empty_part() {
  let field = construct_field(
    "
    .b.b..
    b.zAb.
    .b.b..
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(field.cell(field.to_pos(1, 1)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(3, 1)).is_putting_allowed());
}

#[test]
fn should_not_leave_empty_inside() {
  let field = construct_field(
    "
    .aaaa..
    a....a.
    a.b...a
    .z.bC.a
    a.b...a
    a....a.
    .aaaa..
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(!field.cell(field.to_pos(2, 3)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(2, 4)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(2, 2)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 3)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(3, 3)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 1)).is_putting_allowed());
}

#[test]
fn a_hole_inside_a_surrounding() {
  let field = construct_field(
    "
    ....c....
    ...c.c...
    ..c...c..
    .c..a..c.
    c..a.a..c
    .c..a..c.
    ..c...c..
    ...cBc...
    ....d....
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(!field.cell(field.to_pos(4, 4)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(4, 1)).is_putting_allowed());
}

#[test]
fn a_hole_inside_a_surrounding_after_control_surrounding() {
  let field = construct_field(
    "
    ....b....
    ...b.b...
    ..b...b..
    .b..a..b.
    b..a.a..b
    .b..a..b.
    ..b...b..
    ...bCb...
    ....b....
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(!field.cell(field.to_pos(4, 4)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(4, 1)).is_putting_allowed());
}

#[test]
fn surrounding_does_not_expand() {
  let field = construct_field(
    "
    ....a....
    ...a.a...
    ..a.a.a..
    .a.a.a.a.
    a.a.aBa.a
    .a.a.a.a.
    ..a.a.a..
    ...a.a...
    ....a....
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(field.cell(field.to_pos(6, 3)).is_putting_allowed());
  assert!(field.cell(field.to_pos(4, 3)).is_putting_allowed());
  assert!(field.cell(field.to_pos(4, 5)).is_putting_allowed());
  assert!(field.cell(field.to_pos(6, 5)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(5, 4)).is_putting_allowed());
}

#[test]
fn two_surroundings_with_common_border() {
  let field = construct_field(
    "
    .a..
    aAa.
    .bAa
    ..a.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 2);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn two_surroundings_with_common_dot() {
  let field = construct_field(
    "
    .a.a.
    aAbAa
    .a.a.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 2);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn three_surroundings_with_common_borders() {
  let field = construct_field(
    "
    ..a..
    .aAa.
    ..bAa
    .aAa.
    ..a..
    "
  );
  assert_eq!(field.captured_count(Player::Red), 3);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn undo_check() {
  fn prop(width_seed: u32, height_seed: u32, seed: u64) -> TestResult {
    let width = width_seed % 30;
    let height = height_seed % 30;
    if width < 3 || height < 3 {
      return TestResult::discard();
    }
    let seed_array = [3, seed as u32, 7, (seed >> 32) as u32];
    let mut rng = XorShiftRng::from_seed(seed_array);
    let mut moves = (field::min_pos(width) .. field::max_pos(width, height) + 1).collect::<Vec<Pos>>();
    rng.shuffle(&mut moves);
    let zobrist = Arc::new(Zobrist::new(field::length(width, height) * 2, &mut rng));
    let mut field = Field::new(width, height, zobrist);
    let mut player = Player::Red;
    for pos in moves {
      if field.is_putting_allowed(pos) {
        player = player.next();
        let field_before = field.clone();
        field.put_point(pos, player);
        field.undo();
        if field_before != field {
          return TestResult::failed();
        }
        field.put_point(pos, player);
      }
    }
    TestResult::passed()
  }
  quickcheck::quickcheck(prop as fn(u32, u32, u64) -> TestResult);
}
<commit_msg>Small fix.<commit_after>use std::ascii::AsciiExt;
use std::sync::Arc;
use rand::{Rng, XorShiftRng, SeedableRng};
use quickcheck;
use quickcheck::TestResult;
use player::Player;
use zobrist::Zobrist;
use field;
use field::{Pos, Field};

fn construct_field(image: &str) -> Field {
  let lines = image.split('\n').map(|line| line.trim_matches(' ')).filter(|line| !line.is_empty()).collect::<Vec<&str>>();
  let height = lines.len() as u32;
  assert!(height > 0);
  let width = lines.first().unwrap().len() as u32;
  assert!(lines.iter().all(|line| line.len() as u32 == width));
  let mut moves = lines.into_iter().enumerate().flat_map(|(y, line)|
    line.chars().enumerate().filter(|&(_, c)| c.to_ascii_lowercase() != c.to_ascii_uppercase()).map(move |(x, c)| (c, x as u32, y as u32))
  ).collect::<Vec<(char, u32, u32)>>();
  moves.sort_by(|&(c1, _, _), &(c2, _, _)| (c1.to_ascii_lowercase(), c1.is_lowercase()).cmp(&(c2.to_ascii_lowercase(), c2.is_lowercase())));
  let mut rng = XorShiftRng::new_unseeded();
  let zobrist = Arc::new(Zobrist::new(field::length(width, height) * 2, &mut rng));
  let mut field = Field::new(width, height, zobrist);
  for (c, x, y) in moves.into_iter() {
    let player = Player::from_bool(c.is_uppercase());
    let pos = field.to_pos(x, y);
    field.put_point(pos, player);
  }
  field
}

#[test]
fn simple_surround() {
  let field = construct_field(
    "
    .a.
    cBa
    .a.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(!field.cell(field.to_pos(1, 1)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(0, 1)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 0)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 2)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(2, 1)).is_putting_allowed());
}

#[test]
fn surround_empty_territory() {
  let field = construct_field(
    "
    .a.
    a.a
    .a.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 0);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(field.cell(field.to_pos(1, 1)).is_putting_allowed());
  assert!(field.cell(field.to_pos(1, 1)).is_empty_base());
  assert_eq!(field.cell(field.to_pos(1, 1)).get_empty_base_player(), Some(Player::Red));
  assert!(!field.cell(field.to_pos(0, 1)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 0)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 2)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(2, 1)).is_putting_allowed());
}

#[test]
fn move_priority() {
  let field = construct_field(
    "
    .aB.
    aCaB
    .aB.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 0);
  assert_eq!(field.captured_count(Player::Black), 1);
}

#[test]
fn move_priority_big() {
  let field = construct_field(
    "
    .B..
    BaB.
    aCaB
    .aB.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 0);
  assert_eq!(field.captured_count(Player::Black), 2);
}

#[test]
fn onion_surroundings() {
  let field = construct_field(
    "
    ...c...
    ..cBc..
    .cBaBc.
    ..cBc..
    ...c...
    "
  );
  assert_eq!(field.captured_count(Player::Red), 4);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn apply_control_surrounding_in_same_turn() {
  let field = construct_field(
    "
    .a.
    aBa
    .a.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn double_surround() {
  let field = construct_field(
    "
    .b.b..
    bAzAb.
    .b.b..
    "
  );
  assert_eq!(field.captured_count(Player::Red), 2);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn double_surround_with_empty_part() {
  let field = construct_field(
    "
    .b.b..
    b.zAb.
    .b.b..
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(field.cell(field.to_pos(1, 1)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(3, 1)).is_putting_allowed());
}

#[test]
fn should_not_leave_empty_inside() {
  let field = construct_field(
    "
    .aaaa..
    a....a.
    a.b...a
    .z.bC.a
    a.b...a
    a....a.
    .aaaa..
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(!field.cell(field.to_pos(2, 3)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(2, 4)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(2, 2)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 3)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(3, 3)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(1, 1)).is_putting_allowed());
}

#[test]
fn a_hole_inside_a_surrounding() {
  let field = construct_field(
    "
    ....c....
    ...c.c...
    ..c...c..
    .c..a..c.
    c..a.a..c
    .c..a..c.
    ..c...c..
    ...cBc...
    ....d....
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(!field.cell(field.to_pos(4, 4)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(4, 1)).is_putting_allowed());
}

#[test]
fn a_hole_inside_a_surrounding_after_control_surrounding() {
  let field = construct_field(
    "
    ....b....
    ...b.b...
    ..b...b..
    .b..a..b.
    b..a.a..b
    .b..a..b.
    ..b...b..
    ...bCb...
    ....b....
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(!field.cell(field.to_pos(4, 4)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(4, 1)).is_putting_allowed());
}

#[test]
fn surrounding_does_not_expand() {
  let field = construct_field(
    "
    ....a....
    ...a.a...
    ..a.a.a..
    .a.a.a.a.
    a.a.aBa.a
    .a.a.a.a.
    ..a.a.a..
    ...a.a...
    ....a....
    "
  );
  assert_eq!(field.captured_count(Player::Red), 1);
  assert_eq!(field.captured_count(Player::Black), 0);
  assert!(field.cell(field.to_pos(6, 3)).is_putting_allowed());
  assert!(field.cell(field.to_pos(4, 3)).is_putting_allowed());
  assert!(field.cell(field.to_pos(4, 5)).is_putting_allowed());
  assert!(field.cell(field.to_pos(6, 5)).is_putting_allowed());
  assert!(!field.cell(field.to_pos(5, 4)).is_putting_allowed());
}

#[test]
fn two_surroundings_with_common_border() {
  let field = construct_field(
    "
    .a..
    aAa.
    .bAa
    ..a.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 2);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn two_surroundings_with_common_dot() {
  let field = construct_field(
    "
    .a.a.
    aAbAa
    .a.a.
    "
  );
  assert_eq!(field.captured_count(Player::Red), 2);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn three_surroundings_with_common_borders() {
  let field = construct_field(
    "
    ..a..
    .aAa.
    ..bAa
    .aAa.
    ..a..
    "
  );
  assert_eq!(field.captured_count(Player::Red), 3);
  assert_eq!(field.captured_count(Player::Black), 0);
}

#[test]
fn undo_check() {
  fn prop(width_seed: u32, height_seed: u32, seed: u64) -> TestResult {
    let width = width_seed % 30;
    let height = height_seed % 30;
    if width < 3 || height < 3 {
      return TestResult::discard();
    }
    let seed_array = [3, seed as u32, 7, (seed >> 32) as u32];
    let mut rng = XorShiftRng::from_seed(seed_array);
    let mut moves = (field::min_pos(width) .. field::max_pos(width, height) + 1).collect::<Vec<Pos>>();
    rng.shuffle(&mut moves);
    let zobrist = Arc::new(Zobrist::new(field::length(width, height) * 2, &mut rng));
    let mut field = Field::new(width, height, zobrist);
    let mut player = Player::Red;
    for pos in moves {
      if field.is_putting_allowed(pos) {
        player = player.next();
        let field_before = field.clone();
        field.put_point(pos, player);
        field.undo();
        if field_before != field {
          return TestResult::failed();
        }
        field.put_point(pos, player);
      }
    }
    TestResult::passed()
  }
  quickcheck::quickcheck(prop as fn(u32, u32, u64) -> TestResult);
}
<|endoftext|>


<commit_before>use std::fmt;

pub fn flatten_ok<I, T, E>(iter: I) -> FlattenOk<I, T, E>
where
    I: Iterator<Item = Result<T, E>>,
    T: IntoIterator,
{
    FlattenOk { iter, inner: None }
}

/// An iterator adaptor that flattens `Result::Ok` values and
/// allows `Result::Err` values through unchanged.
///
/// See [`.flatten_ok()`](crate::Itertools::flatten_ok) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct FlattenOk<I, T, E>
where
    I: Iterator<Item = Result<T, E>>,
    T: IntoIterator,
{
    iter: I,
    inner: Option<T::IntoIter>,
}

impl<I, T, E> Iterator for FlattenOk<I, T, E>
where
    I: Iterator<Item = Result<T, E>>,
    T: IntoIterator,
{
    type Item = Result<T::Item, E>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(inner) = &mut self.inner {
                if let Some(item) = inner.next() {
                    return Some(Ok(item));
                } else {
                    self.inner = None;
                }
            }

            match self.iter.next() {
                Some(Ok(ok)) => self.inner = Some(ok.into_iter()),
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
    }
}

impl<I, T, E> Clone for FlattenOk<I, T, E>
where
    I: Iterator<Item = Result<T, E>> + Clone,
    T: IntoIterator,
    T::IntoIter: Clone,
{
    #[inline]
    clone_fields!(iter, inner);
}

impl<I, T, E> fmt::Debug for FlattenOk<I, T, E>
where
    I: Iterator<Item = Result<T, E>> + fmt::Debug,
    T: IntoIterator,
    T::IntoIter: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FlattenOk")
            .field("iter", &self.iter)
            .field("inner", &self.inner)
            .finish()
    }
}
<commit_msg>add FusedIterator impl for FlattenOk<commit_after>use std::{fmt, iter::FusedIterator};

pub fn flatten_ok<I, T, E>(iter: I) -> FlattenOk<I, T, E>
where
    I: Iterator<Item = Result<T, E>>,
    T: IntoIterator,
{
    FlattenOk { iter, inner: None }
}

/// An iterator adaptor that flattens `Result::Ok` values and
/// allows `Result::Err` values through unchanged.
///
/// See [`.flatten_ok()`](crate::Itertools::flatten_ok) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct FlattenOk<I, T, E>
where
    I: Iterator<Item = Result<T, E>>,
    T: IntoIterator,
{
    iter: I,
    inner: Option<T::IntoIter>,
}

impl<I, T, E> Iterator for FlattenOk<I, T, E>
where
    I: Iterator<Item = Result<T, E>>,
    T: IntoIterator,
{
    type Item = Result<T::Item, E>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(inner) = &mut self.inner {
                if let Some(item) = inner.next() {
                    return Some(Ok(item));
                } else {
                    // This is necessary for the iterator to implement `FusedIterator`
                    // with only the orginal iterator being fused.
                    self.inner = None;
                }
            }

            match self.iter.next() {
                Some(Ok(ok)) => self.inner = Some(ok.into_iter()),
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
    }
}

impl<I, T, E> Clone for FlattenOk<I, T, E>
where
    I: Iterator<Item = Result<T, E>> + Clone,
    T: IntoIterator,
    T::IntoIter: Clone,
{
    #[inline]
    clone_fields!(iter, inner);
}

impl<I, T, E> fmt::Debug for FlattenOk<I, T, E>
where
    I: Iterator<Item = Result<T, E>> + fmt::Debug,
    T: IntoIterator,
    T::IntoIter: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FlattenOk")
            .field("iter", &self.iter)
            .field("inner", &self.inner)
            .finish()
    }
}

/// Only the iterator being flattened needs to implement [`FusedIterator`].
impl<I, T, E> FusedIterator for FlattenOk<I, T, E>
where
    I: FusedIterator<Item = Result<T, E>>,
    T: IntoIterator,
{
}
<|endoftext|>