<commit_before>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(all(feature = "full", feature = "fold"))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `libsyntax`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `libsyntax_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `libsyntax`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

#[macro_use]
extern crate quote;
extern crate rayon;
extern crate regex;
extern crate rustc_data_structures;
extern crate syn;
extern crate syntax;
extern crate walkdir;

use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use syntax::ast;
use syntax::ptr::P;
use walkdir::{DirEntry, WalkDir};

use std::fs::File;
use std::io::Read;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};

use common::eq::SpanlessEq;
use common::parse;

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(common::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            // Our version of `libsyntax` can't parse this tests
            if path
                .to_str()
                .unwrap()
                .ends_with("optional_comma_in_match_arm.rs")
            {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let exprs = collect_exprs(file);
                    test_expressions(exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    syntax::with_globals(|| {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let libsyntax_ast = if let Some(e) = libsyntax_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::libsyntax_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &libsyntax_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, libsyntax_ast);
            }
        }
    });

    (passed, failed)
}

fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::libsyntax_expr(input).and_then(libsyntax_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on libsyntax objects.
fn libsyntax_brackets(libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_data_structures::small_vec::OneVector;
    use rustc_data_structures::thin_vec::ThinVec;
    use syntax::ast::{Expr, ExprKind, Field, Mac, Pat, Stmt, StmtKind, Ty};
    use syntax::ext::quote::rt::DUMMY_SP;
    use syntax::fold::{self, Folder};

    struct BracketsFolder {
        failed: bool,
    };
    impl Folder for BracketsFolder {
        fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
            e.map(|e| match e.node {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::IfLet(..) => {
                    fold::noop_fold_expr(e, self)
                }
                _ => Expr {
                    id: ast::DUMMY_NODE_ID,
                    node: ExprKind::Paren(P(fold::noop_fold_expr(e, self))),
                    span: DUMMY_SP,
                    attrs: ThinVec::new(),
                },
            })
        }

        fn fold_field(&mut self, f: Field) -> Field {
            Field {
                expr: if f.is_shorthand {
                    f.expr.map(|e| fold::noop_fold_expr(e, self))
                } else {
                    self.fold_expr(f.expr)
                },
                ..f
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
            pat
        }

        fn fold_ty(&mut self, ty: P<Ty>) -> P<Ty> {
            ty
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> OneVector<Stmt> {
            let node = match stmt.node {
                // Don't wrap toplevel expressions in statements.
                StmtKind::Expr(e) => StmtKind::Expr(e.map(|e| fold::noop_fold_expr(e, self))),
                StmtKind::Semi(e) => StmtKind::Semi(e.map(|e| fold::noop_fold_expr(e, self))),
                s => s,
            };

            OneVector::from_vec(vec![Stmt { node, ..stmt }])
        }

        fn fold_mac(&mut self, mac: Mac) -> Mac {
            // By default when folding over macros, libsyntax panics. This is
            // because it's usually not what you want, you want to run after
            // macro expansion. We do want to do that (syn doesn't do macro
            // expansion), so we implement fold_mac to just return the macro
            // unchanged.
            mac
        }
    }

    let mut folder = BracketsFolder { failed: false };
    let e = folder.fold_expr(libsyntax_expr);
    if folder.failed {
        None
    } else {
        Some(e)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::*;
    use syn::*;

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                node => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, node)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::*;
    use syn::punctuated::Punctuated;
    use syn::*;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            self.0.push(expr);

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<commit_msg>OneVector type alias has been removed<commit_after>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(all(feature = "full", feature = "fold"))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `libsyntax`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `libsyntax_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `libsyntax`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

#[macro_use]
extern crate quote;
extern crate rayon;
extern crate regex;
extern crate rustc_data_structures;
#[macro_use]
extern crate smallvec;
extern crate syn;
extern crate syntax;
extern crate walkdir;

use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use syntax::ast;
use syntax::ptr::P;
use walkdir::{DirEntry, WalkDir};

use std::fs::File;
use std::io::Read;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};

use common::eq::SpanlessEq;
use common::parse;

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(common::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            // Our version of `libsyntax` can't parse this tests
            if path
                .to_str()
                .unwrap()
                .ends_with("optional_comma_in_match_arm.rs")
            {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let exprs = collect_exprs(file);
                    test_expressions(exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    syntax::with_globals(|| {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let libsyntax_ast = if let Some(e) = libsyntax_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::libsyntax_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &libsyntax_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, libsyntax_ast);
            }
        }
    });

    (passed, failed)
}

fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::libsyntax_expr(input).and_then(libsyntax_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on libsyntax objects.
fn libsyntax_brackets(libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_data_structures::thin_vec::ThinVec;
    use smallvec::SmallVec;
    use syntax::ast::{Expr, ExprKind, Field, Mac, Pat, Stmt, StmtKind, Ty};
    use syntax::ext::quote::rt::DUMMY_SP;
    use syntax::fold::{self, Folder};

    struct BracketsFolder {
        failed: bool,
    };
    impl Folder for BracketsFolder {
        fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
            e.map(|e| match e.node {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::IfLet(..) => {
                    fold::noop_fold_expr(e, self)
                }
                _ => Expr {
                    id: ast::DUMMY_NODE_ID,
                    node: ExprKind::Paren(P(fold::noop_fold_expr(e, self))),
                    span: DUMMY_SP,
                    attrs: ThinVec::new(),
                },
            })
        }

        fn fold_field(&mut self, f: Field) -> Field {
            Field {
                expr: if f.is_shorthand {
                    f.expr.map(|e| fold::noop_fold_expr(e, self))
                } else {
                    self.fold_expr(f.expr)
                },
                ..f
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
            pat
        }

        fn fold_ty(&mut self, ty: P<Ty>) -> P<Ty> {
            ty
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> SmallVec<[Stmt; 1]> {
            let node = match stmt.node {
                // Don't wrap toplevel expressions in statements.
                StmtKind::Expr(e) => StmtKind::Expr(e.map(|e| fold::noop_fold_expr(e, self))),
                StmtKind::Semi(e) => StmtKind::Semi(e.map(|e| fold::noop_fold_expr(e, self))),
                s => s,
            };

            smallvec![Stmt { node, ..stmt }]
        }

        fn fold_mac(&mut self, mac: Mac) -> Mac {
            // By default when folding over macros, libsyntax panics. This is
            // because it's usually not what you want, you want to run after
            // macro expansion. We do want to do that (syn doesn't do macro
            // expansion), so we implement fold_mac to just return the macro
            // unchanged.
            mac
        }
    }

    let mut folder = BracketsFolder { failed: false };
    let e = folder.fold_expr(libsyntax_expr);
    if folder.failed {
        None
    } else {
        Some(e)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::*;
    use syn::*;

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                node => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, node)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::*;
    use syn::punctuated::Punctuated;
    use syn::*;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            self.0.push(expr);

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-2019 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

//! Error handling

use std::{error, fmt, io};

use futures_channel::mpsc;

use crate::resp;

#[derive(Debug)]
pub enum Error {
    /// A non-specific internal error that prevented an operation from completing
    Internal(String),

    /// An IO error occurred
    IO(io::Error),

    /// A RESP parsing/serialising error occurred
    RESP(String, Option<resp::RespValue>),

    /// A remote error
    Remote(String),

    /// Error creating a connection, or an error with a connection being closed unexpectedly
    Connection(ConnectionReason),

    /// An unexpected error.  In this context "unexpected" means
    /// "unexpected because we check ahead of time", it used to maintain the type signature of
    /// chains of futures; but it occurring at runtime should be considered a catastrophic
    /// failure.
    ///
    /// If any error is propagated this way that needs to be handled, then it should be made into
    /// a proper option.
    Unexpected(String),
}

pub(crate) fn internal(msg: impl Into<String>) -> Error {
    Error::Internal(msg.into())
}

pub(crate) fn unexpected(msg: impl Into<String>) -> Error {
    Error::Unexpected(msg.into())
}

pub(crate) fn resp(msg: impl Into<String>, resp: resp::RespValue) -> Error {
    Error::RESP(msg.into(), Some(resp))
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl<T: 'static + Send> From<mpsc::TrySendError<T>> for Error {
    fn from(err: mpsc::TrySendError<T>) -> Error {
        Error::Unexpected(format!("Cannot write to channel: {}", err))
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Internal(ref s) => s,
            Error::IO(ref err) => err.description(),
            Error::RESP(ref s, _) => s,
            Error::Remote(ref s) => s,
            Error::Connection(ConnectionReason::Connected) => "Connection already established",
            Error::Connection(ConnectionReason::Connecting) => "Connection in progress",
            Error::Connection(ConnectionReason::ConnectionFailed) => {
                "The last attempt to establish a connection failed"
            }
            Error::Connection(ConnectionReason::NotConnected) => "Connection has been closed",
            Error::Unexpected(ref err) => err,
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            Error::Internal(_) => None,
            Error::IO(ref err) => Some(err),
            Error::RESP(_, _) => None,
            Error::Remote(_) => None,
            Error::Connection(_) => None,
            Error::Unexpected(_) => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        fmt::Display::fmt(self.description(), f)
    }
}

/// Details of a `ConnectionError`
#[derive(Debug)]
pub enum ConnectionReason {
    /// An attempt to use a connection while it is in the "connecting" state, clients should try
    /// again
    Connecting,
    /// An attempt was made to reconnect after a connection was established, clients should try
    /// again
    Connected,
    /// Connection failed - this can be returned from a call to reconnect, the actual error will be
    /// sent to the client at the next call
    ConnectionFailed,
    /// The connection is not currently connected, the connection will reconnect asynchronously,
    /// clients should try again
    NotConnected,
}
<commit_msg>Remove deprecated Error::description and Error::cause<commit_after>/*
 * Copyright 2017-2019 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

//! Error handling

use std::{error, fmt, io};

use futures_channel::mpsc;

use crate::resp;

#[derive(Debug)]
pub enum Error {
    /// A non-specific internal error that prevented an operation from completing
    Internal(String),

    /// An IO error occurred
    IO(io::Error),

    /// A RESP parsing/serialising error occurred
    RESP(String, Option<resp::RespValue>),

    /// A remote error
    Remote(String),

    /// Error creating a connection, or an error with a connection being closed unexpectedly
    Connection(ConnectionReason),

    /// An unexpected error.  In this context "unexpected" means
    /// "unexpected because we check ahead of time", it used to maintain the type signature of
    /// chains of futures; but it occurring at runtime should be considered a catastrophic
    /// failure.
    ///
    /// If any error is propagated this way that needs to be handled, then it should be made into
    /// a proper option.
    Unexpected(String),
}

pub(crate) fn internal(msg: impl Into<String>) -> Error {
    Error::Internal(msg.into())
}

pub(crate) fn unexpected(msg: impl Into<String>) -> Error {
    Error::Unexpected(msg.into())
}

pub(crate) fn resp(msg: impl Into<String>, resp: resp::RespValue) -> Error {
    Error::RESP(msg.into(), Some(resp))
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl<T: 'static + Send> From<mpsc::TrySendError<T>> for Error {
    fn from(err: mpsc::TrySendError<T>) -> Error {
        Error::Unexpected(format!("Cannot write to channel: {}", err))
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self {
            Error::IO(err) => Some(err),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::Internal(s) => write!(f, "{}", s),
            Error::IO(err) => write!(f, "{}", err),
            Error::RESP(s, _) => write!(f, "{}", s),
            Error::Remote(s) => write!(f, "{}", s),
            Error::Connection(ConnectionReason::Connected) => {
                write!(f, "Connection already established")
            }
            Error::Connection(ConnectionReason::Connecting) => write!(f, "Connection in progress"),
            Error::Connection(ConnectionReason::ConnectionFailed) => {
                write!(f, "The last attempt to establish a connection failed")
            }
            Error::Connection(ConnectionReason::NotConnected) => {
                write!(f, "Connection has been closed")
            }
            Error::Unexpected(err) => write!(f, "{}", err),
        }
    }
}

/// Details of a `ConnectionError`
#[derive(Debug)]
pub enum ConnectionReason {
    /// An attempt to use a connection while it is in the "connecting" state, clients should try
    /// again
    Connecting,
    /// An attempt was made to reconnect after a connection was established, clients should try
    /// again
    Connected,
    /// Connection failed - this can be returned from a call to reconnect, the actual error will be
    /// sent to the client at the next call
    ConnectionFailed,
    /// The connection is not currently connected, the connection will reconnect asynchronously,
    /// clients should try again
    NotConnected,
}
<|endoftext|>


<commit_before>//! Error and Result module.
use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;

use httparse;
use openssl::ssl::error::SslError;
use url;

use self::Error::{
    Method,
    Uri,
    Version,
    Header,
    Status,
    Io,
    Ssl,
    TooLarge
};

/// Result type often returned from methods that can have hyper `Error`s.
pub type Result<T> = ::std::result::Result<T, Error>;

/// A set of errors that can occur parsing HTTP streams.
#[derive(Debug)]
pub enum Error {
    /// An invalid `Method`, such as `GE,T`.
    Method,
    /// An invalid `RequestUri`, such as `exam ple.domain`.
    Uri(url::ParseError),
    /// An invalid `HttpVersion`, such as `HTP/1.1`
    Version,
    /// An invalid `Header`.
    Header,
    /// A message head is too large to be reasonable.
    TooLarge,
    /// An invalid `Status`, such as `1337 ELITE`.
    Status,
    /// An `io::Error` that occurred while trying to read or write to a network stream.
    Io(IoError),
    /// An error from the `openssl` library.
    Ssl(SslError)
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Method => "Invalid Method specified",
            Version => "Invalid HTTP version specified",
            Header => "Invalid Header provided",
            TooLarge => "Message head is too large",
            Status => "Invalid Status provided",
            Uri(ref e) => e.description(),
            Io(ref e) => e.description(),
            Ssl(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Io(ref error) => Some(error),
            Ssl(ref error) => Some(error),
            Uri(ref error) => Some(error),
            _ => None,
        }
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Io(err)
    }
}

impl From<url::ParseError> for Error {
    fn from(err: url::ParseError) -> Error {
        Uri(err)
    }
}

impl From<SslError> for Error {
    fn from(err: SslError) -> Error {
        match err {
            SslError::StreamError(err) => Io(err),
            err => Ssl(err),
        }
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Error {
        match err {
            httparse::Error::HeaderName => Header,
            httparse::Error::HeaderValue => Header,
            httparse::Error::NewLine => Header,
            httparse::Error::Status => Status,
            httparse::Error::Token => Header,
            httparse::Error::TooManyHeaders => TooLarge,
            httparse::Error::Version => Version,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::error::Error as StdError;
    use std::io;
    use httparse;
    use openssl::ssl::error::SslError;
    use url;
    use super::Error;
    use super::Error::*;

    #[test]
    fn test_cause() {
        let orig = io::Error::new(io::ErrorKind::Other, "other");
        let desc = orig.description().to_owned();
        let e = Io(orig);
        assert_eq!(e.cause().unwrap().description(), desc);
    }

    macro_rules! from {
        ($from:expr => $error:pat) => {
            match Error::from($from) {
                e @ $error => {
                    assert!(e.description().len() > 5);
                } ,
                _ => panic!("{:?}", $from)
            }
        }
    }

    macro_rules! from_and_cause {
        ($from:expr => $error:pat) => {
            match Error::from($from) {
                e @ $error => {
                    let desc = e.cause().unwrap().description();
                    assert_eq!(desc, $from.description().to_owned());
                    assert_eq!(desc, e.description());
                },
                _ => panic!("{:?}", $from)
            }
        }
    }

    #[test]
    fn test_from() {

        from_and_cause!(io::Error::new(io::ErrorKind::Other, "other") => Io(..));
        from_and_cause!(url::ParseError::EmptyHost => Uri(..));
        from_and_cause!(SslError::SslSessionClosed => Ssl(..));

        from!(SslError::StreamError(io::Error::new(io::ErrorKind::Other, "ssl negotiation")) => Io(..));

        from!(httparse::Error::HeaderName => Header);
        from!(httparse::Error::HeaderName => Header);
        from!(httparse::Error::HeaderValue => Header);
        from!(httparse::Error::NewLine => Header);
        from!(httparse::Error::Status => Status);
        from!(httparse::Error::Token => Header);
        from!(httparse::Error::TooManyHeaders => TooLarge);
        from!(httparse::Error::Version => Version);
    }
}
<commit_msg>feat(http2): add new error variant for HTTP/2<commit_after>//! Error and Result module.
use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;

use httparse;
use openssl::ssl::error::SslError;
use url;
use solicit::http::HttpError as Http2Error;

use self::Error::{
    Method,
    Uri,
    Version,
    Header,
    Status,
    Io,
    Ssl,
    TooLarge,
    Http2,
};

/// Result type often returned from methods that can have hyper `Error`s.
pub type Result<T> = ::std::result::Result<T, Error>;

/// A set of errors that can occur parsing HTTP streams.
#[derive(Debug)]
pub enum Error {
    /// An invalid `Method`, such as `GE,T`.
    Method,
    /// An invalid `RequestUri`, such as `exam ple.domain`.
    Uri(url::ParseError),
    /// An invalid `HttpVersion`, such as `HTP/1.1`
    Version,
    /// An invalid `Header`.
    Header,
    /// A message head is too large to be reasonable.
    TooLarge,
    /// An invalid `Status`, such as `1337 ELITE`.
    Status,
    /// An `io::Error` that occurred while trying to read or write to a network stream.
    Io(IoError),
    /// An error from the `openssl` library.
    Ssl(SslError),
    /// An HTTP/2-specific error, coming from the `solicit` library.
    Http2(Http2Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Method => "Invalid Method specified",
            Version => "Invalid HTTP version specified",
            Header => "Invalid Header provided",
            TooLarge => "Message head is too large",
            Status => "Invalid Status provided",
            Uri(ref e) => e.description(),
            Io(ref e) => e.description(),
            Ssl(ref e) => e.description(),
            Http2(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Io(ref error) => Some(error),
            Ssl(ref error) => Some(error),
            Uri(ref error) => Some(error),
            Http2(ref error) => Some(error),
            _ => None,
        }
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Io(err)
    }
}

impl From<url::ParseError> for Error {
    fn from(err: url::ParseError) -> Error {
        Uri(err)
    }
}

impl From<SslError> for Error {
    fn from(err: SslError) -> Error {
        match err {
            SslError::StreamError(err) => Io(err),
            err => Ssl(err),
        }
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Error {
        match err {
            httparse::Error::HeaderName => Header,
            httparse::Error::HeaderValue => Header,
            httparse::Error::NewLine => Header,
            httparse::Error::Status => Status,
            httparse::Error::Token => Header,
            httparse::Error::TooManyHeaders => TooLarge,
            httparse::Error::Version => Version,
        }
    }
}

impl From<Http2Error> for Error {
    fn from(err: Http2Error) -> Error {
        Error::Http2(err)
    }
}

#[cfg(test)]
mod tests {
    use std::error::Error as StdError;
    use std::io;
    use httparse;
    use openssl::ssl::error::SslError;
    use solicit::http::HttpError as Http2Error;
    use url;
    use super::Error;
    use super::Error::*;

    #[test]
    fn test_cause() {
        let orig = io::Error::new(io::ErrorKind::Other, "other");
        let desc = orig.description().to_owned();
        let e = Io(orig);
        assert_eq!(e.cause().unwrap().description(), desc);
    }

    macro_rules! from {
        ($from:expr => $error:pat) => {
            match Error::from($from) {
                e @ $error => {
                    assert!(e.description().len() > 5);
                } ,
                _ => panic!("{:?}", $from)
            }
        }
    }

    macro_rules! from_and_cause {
        ($from:expr => $error:pat) => {
            match Error::from($from) {
                e @ $error => {
                    let desc = e.cause().unwrap().description();
                    assert_eq!(desc, $from.description().to_owned());
                    assert_eq!(desc, e.description());
                },
                _ => panic!("{:?}", $from)
            }
        }
    }

    #[test]
    fn test_from() {

        from_and_cause!(io::Error::new(io::ErrorKind::Other, "other") => Io(..));
        from_and_cause!(url::ParseError::EmptyHost => Uri(..));
        from_and_cause!(SslError::SslSessionClosed => Ssl(..));
        from_and_cause!(Http2Error::UnknownStreamId => Http2(..));

        from!(SslError::StreamError(io::Error::new(io::ErrorKind::Other, "ssl negotiation")) => Io(..));

        from!(httparse::Error::HeaderName => Header);
        from!(httparse::Error::HeaderName => Header);
        from!(httparse::Error::HeaderValue => Header);
        from!(httparse::Error::NewLine => Header);
        from!(httparse::Error::Status => Status);
        from!(httparse::Error::Token => Header);
        from!(httparse::Error::TooManyHeaders => TooLarge);
        from!(httparse::Error::Version => Version);
    }
}
<|endoftext|>


<commit_before>use std::convert::From;
use std::{error, io, fmt};

use ber::error::ASN1Error;

pub enum LDAPError
{
    ASN1(ASN1Error),
    Io(io::Error),
}

impl fmt::Display for LDAPError
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        write!(f, "{:?}", *self)
    }
}

impl fmt::Debug for LDAPError
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        write!(f, "Error: {}", error::Error::description(self))
    }
}

impl error::Error for LDAPError
{
    fn description(&self) -> &str
    {
        match *self
        {
            LDAPError::ASN1(ref x) => error::Error::description(x),
            LDAPError::Io(ref x) => error::Error::description(x),
        }
    }
}

impl From<io::Error> for LDAPError
{
    fn from(err: io::Error) -> LDAPError
    {
        LDAPError::Io(err)
    }
}

impl From<ASN1Error> for LDAPError
{
    fn from(err: ASN1Error) -> LDAPError
    {
        match err
        {
            ASN1Error::Io(e) => LDAPError::from(e),
            _ => LDAPError::ASN1(err),
        }
    }
}
<commit_msg>Adds Unspecified error type<commit_after>use std::convert::From;
use std::{error, io, fmt};

use ber::error::ASN1Error;

pub enum LDAPError
{
    ASN1(ASN1Error),
    Io(io::Error),
    Other,
}

impl fmt::Display for LDAPError
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        write!(f, "{:?}", *self)
    }
}

impl fmt::Debug for LDAPError
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        write!(f, "Error: {}", error::Error::description(self))
    }
}

impl error::Error for LDAPError
{
    fn description(&self) -> &str
    {
        match *self
        {
            LDAPError::ASN1(ref x) => error::Error::description(x),
            LDAPError::Io(ref x) => error::Error::description(x),
            LDAPError::Other => "Error occured",
        }
    }
}

impl From<io::Error> for LDAPError
{
    fn from(err: io::Error) -> LDAPError
    {
        LDAPError::Io(err)
    }
}

impl From<ASN1Error> for LDAPError
{
    fn from(err: ASN1Error) -> LDAPError
    {
        match err
        {
            ASN1Error::Io(e) => LDAPError::from(e),
            _ => LDAPError::ASN1(err),
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;

pub type Result<T> = ::std::result::Result<T, Error>;

/// An enumeration over JPEG features (currently) unsupported by this library.
///
/// Support for features listed here may be included in future versions of this library.
#[derive(Debug)]
pub enum UnsupportedFeature {
    /// Hierarchical JPEG.
    Hierarchical,
    /// Lossless JPEG.
    Lossless,
    /// JPEG using arithmetic entropy coding instead of Huffman coding.
    ArithmeticEntropyCoding,
    /// Sample precision in bits. 8 bit sample precision is what is currently supported.
    SamplePrecision(u8),
    /// Number of components in an image. 1, 3 and 4 components are currently supported.
    ComponentCount(u8),
    /// An image can specify a zero height in the frame header and use the DNL (Define Number of
    /// Lines) marker at the end of the first scan to define the number of lines in the frame.
    DNL,
    /// Subsampling ratio.
    SubsamplingRatio,
    /// A subsampling ratio not representable as an integer.
    NonIntegerSubsamplingRatio,
}

/// Errors that can occur while decoding a JPEG image.
#[derive(Debug)]
pub enum Error {
    /// The image is not formatted properly. The string contains detailed information about the
    /// error.
    Format(String),
    /// The image makes use of a JPEG feature not (currently) supported by this library.
    Unsupported(UnsupportedFeature),
    /// An I/O error occurred while decoding the image.
    Io(IoError),
    /// An internal error occurred while decoding the image.
    Internal(Box<dyn StdError + Send + Sync + 'static>), //TODO: not used, can be removed with the next version bump
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Format(ref desc)      => write!(f, "invalid JPEG format: {}", desc),
            Error::Unsupported(ref feat) => write!(f, "unsupported JPEG feature: {:?}", feat),
            Error::Io(ref err)           => err.fmt(f),
            Error::Internal(ref err)     => err.fmt(f),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Format(_)         => "invalid JPEG format",
            Error::Unsupported(_)    => "unsupported JPEG feature",
            Error::Io(ref err)       => err.description(),
            Error::Internal(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&dyn StdError> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::Internal(ref err) => Some(&**err),
            _ => None,
        }
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}
<commit_msg>Don’t use deprecated Error::description<commit_after>use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;

pub type Result<T> = ::std::result::Result<T, Error>;

/// An enumeration over JPEG features (currently) unsupported by this library.
///
/// Support for features listed here may be included in future versions of this library.
#[derive(Debug)]
pub enum UnsupportedFeature {
    /// Hierarchical JPEG.
    Hierarchical,
    /// Lossless JPEG.
    Lossless,
    /// JPEG using arithmetic entropy coding instead of Huffman coding.
    ArithmeticEntropyCoding,
    /// Sample precision in bits. 8 bit sample precision is what is currently supported.
    SamplePrecision(u8),
    /// Number of components in an image. 1, 3 and 4 components are currently supported.
    ComponentCount(u8),
    /// An image can specify a zero height in the frame header and use the DNL (Define Number of
    /// Lines) marker at the end of the first scan to define the number of lines in the frame.
    DNL,
    /// Subsampling ratio.
    SubsamplingRatio,
    /// A subsampling ratio not representable as an integer.
    NonIntegerSubsamplingRatio,
}

/// Errors that can occur while decoding a JPEG image.
#[derive(Debug)]
pub enum Error {
    /// The image is not formatted properly. The string contains detailed information about the
    /// error.
    Format(String),
    /// The image makes use of a JPEG feature not (currently) supported by this library.
    Unsupported(UnsupportedFeature),
    /// An I/O error occurred while decoding the image.
    Io(IoError),
    /// An internal error occurred while decoding the image.
    Internal(Box<dyn StdError + Send + Sync + 'static>), //TODO: not used, can be removed with the next version bump
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Format(ref desc)      => write!(f, "invalid JPEG format: {}", desc),
            Error::Unsupported(ref feat) => write!(f, "unsupported JPEG feature: {:?}", feat),
            Error::Io(ref err)           => err.fmt(f),
            Error::Internal(ref err)     => err.fmt(f),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::Internal(ref err) => Some(&**err),
            _ => None,
        }
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}
<|endoftext|>


<commit_before>use std::io::Error as IOError;

#[derive(Fail, Debug)]
pub enum FatalError {
    #[fail(display = "{}", _0)] IO(#[cause] IOError),

    #[fail(display = "Invalid cargo file format.")] InvalidCargoFileFormat,

    #[fail(display = "Unknown cargo key found: {}", key)] UnknownCargoFileKey { key: String },
}
<commit_msg>Fix rustfmt build break on Travis. (#73)<commit_after>use std::io::Error as IOError;

#[derive(Fail, Debug)]
pub enum FatalError {
    #[fail(display = "{}", _0)]
    IO(#[cause] IOError),

    #[fail(display = "Invalid cargo file format.")]
    InvalidCargoFileFormat,

    #[fail(display = "Unknown cargo key found: {}", key)]
    UnknownCargoFileKey { key: String },
}
<|endoftext|>


<commit_before>//! Definition of Tantivy's error and result.

use std::path::PathBuf;
use std::sync::PoisonError;
use std::{fmt, io};

use thiserror::Error;

use crate::directory::error::{
    Incompatibility, LockError, OpenDirectoryError, OpenReadError, OpenWriteError,
};
use crate::fastfield::FastFieldNotAvailableError;
use crate::{query, schema};

/// Represents a `DataCorruption` error.
///
/// When facing data corruption, tantivy  actually panic or return this error.
pub struct DataCorruption {
    filepath: Option<PathBuf>,
    comment: String,
}

impl DataCorruption {
    /// Creates a `DataCorruption` Error.
    pub fn new(filepath: PathBuf, comment: String) -> DataCorruption {
        DataCorruption {
            filepath: Some(filepath),
            comment,
        }
    }

    /// Creates a `DataCorruption` Error, when the filepath is irrelevant.
    pub fn comment_only<TStr: ToString>(comment: TStr) -> DataCorruption {
        DataCorruption {
            filepath: None,
            comment: comment.to_string(),
        }
    }
}

impl fmt::Debug for DataCorruption {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        write!(f, "Data corruption")?;
        if let Some(ref filepath) = &self.filepath {
            write!(f, " (in file `{:?}`)", filepath)?;
        }
        write!(f, ": {}.", self.comment)?;
        Ok(())
    }
}

/// The library's error enum
#[derive(Debug, Error)]
pub enum TantivyError {
    /// Failed to open the directory.
    #[error("Failed to open the directory: '{0:?}'")]
    OpenDirectoryError(#[from] OpenDirectoryError),
    /// Failed to open a file for read.
    #[error("Failed to open file for read: '{0:?}'")]
    OpenReadError(#[from] OpenReadError),
    /// Failed to open a file for write.
    #[error("Failed to open file for write: '{0:?}'")]
    OpenWriteError(#[from] OpenWriteError),
    /// Index already exists in this directory
    #[error("Index already exists")]
    IndexAlreadyExists,
    /// Failed to acquire file lock
    #[error("Failed to acquire Lockfile: {0:?}. {1:?}")]
    LockFailure(LockError, Option<String>),
    /// IO Error.
    #[error("An IO error occurred: '{0}'")]
    IoError(#[from] io::Error),
    /// Data corruption.
    #[error("Data corrupted: '{0:?}'")]
    DataCorruption(DataCorruption),
    /// A thread holding the locked panicked and poisoned the lock.
    #[error("A thread holding the locked panicked and poisoned the lock")]
    Poisoned,
    /// The provided field name does not exist.
    #[error("The field does not exist: '{0}'")]
    FieldNotFound(String),
    /// Invalid argument was passed by the user.
    #[error("An invalid argument was passed: '{0}'")]
    InvalidArgument(String),
    /// An Error happened in one of the thread.
    #[error("An error occurred in a thread: '{0}'")]
    ErrorInThread(String),
    /// An Error appeared related to opening or creating a index.
    #[error("Missing required index builder argument when open/create index: '{0}'")]
    IndexBuilderMissingArgument(&'static str),
    /// An Error appeared related to the schema.
    #[error("Schema error: '{0}'")]
    SchemaError(String),
    /// System error. (e.g.: We failed spawning a new thread)
    #[error("System error.'{0}'")]
    SystemError(String),
    /// Index incompatible with current version of tantivy
    #[error("{0:?}")]
    IncompatibleIndex(Incompatibility),
}

#[cfg(feature = "quickwit")]
#[derive(Error, Debug)]
#[doc(hidden)]
pub enum AsyncIoError {
    #[error("io::Error `{0}`")]
    Io(#[from] io::Error),
    #[error("Asynchronous API is unsupported by this directory")]
    AsyncUnsupported,
}

#[cfg(feature = "quickwit")]
impl From<AsyncIoError> for TantivyError {
    fn from(async_io_err: AsyncIoError) -> Self {
        match async_io_err {
            AsyncIoError::Io(io_err) => TantivyError::from(io_err),
            AsyncIoError::AsyncUnsupported => {
                TantivyError::SystemError(format!("{:?}", async_io_err))
            }
        }
    }
}

impl From<DataCorruption> for TantivyError {
    fn from(data_corruption: DataCorruption) -> TantivyError {
        TantivyError::DataCorruption(data_corruption)
    }
}
impl From<FastFieldNotAvailableError> for TantivyError {
    fn from(fastfield_error: FastFieldNotAvailableError) -> TantivyError {
        TantivyError::SchemaError(format!("{}", fastfield_error))
    }
}
impl From<LockError> for TantivyError {
    fn from(lock_error: LockError) -> TantivyError {
        TantivyError::LockFailure(lock_error, None)
    }
}

impl From<query::QueryParserError> for TantivyError {
    fn from(parsing_error: query::QueryParserError) -> TantivyError {
        TantivyError::InvalidArgument(format!("Query is invalid. {:?}", parsing_error))
    }
}

impl<Guard> From<PoisonError<Guard>> for TantivyError {
    fn from(_: PoisonError<Guard>) -> TantivyError {
        TantivyError::Poisoned
    }
}

impl From<chrono::ParseError> for TantivyError {
    fn from(err: chrono::ParseError) -> TantivyError {
        TantivyError::InvalidArgument(err.to_string())
    }
}

impl From<schema::DocParsingError> for TantivyError {
    fn from(error: schema::DocParsingError) -> TantivyError {
        TantivyError::InvalidArgument(format!("Failed to parse document {:?}", error))
    }
}

impl From<serde_json::Error> for TantivyError {
    fn from(error: serde_json::Error) -> TantivyError {
        TantivyError::IoError(error.into())
    }
}

impl From<rayon::ThreadPoolBuildError> for TantivyError {
    fn from(error: rayon::ThreadPoolBuildError) -> TantivyError {
        TantivyError::SystemError(error.to_string())
    }
}
<commit_msg>error definitions<commit_after>//! Definition of Tantivy's errors and results.

use std::path::PathBuf;
use std::sync::PoisonError;
use std::{fmt, io};

use thiserror::Error;

use crate::directory::error::{
    Incompatibility, LockError, OpenDirectoryError, OpenReadError, OpenWriteError,
};
use crate::fastfield::FastFieldNotAvailableError;
use crate::{query, schema};

/// Represents a `DataCorruption` error.
///
/// When facing data corruption, tantivy actually panics or returns this error.
pub struct DataCorruption {
    filepath: Option<PathBuf>,
    comment: String,
}

impl DataCorruption {
    /// Creates a `DataCorruption` Error.
    pub fn new(filepath: PathBuf, comment: String) -> DataCorruption {
        DataCorruption {
            filepath: Some(filepath),
            comment,
        }
    }

    /// Creates a `DataCorruption` Error, when the filepath is irrelevant.
    pub fn comment_only<TStr: ToString>(comment: TStr) -> DataCorruption {
        DataCorruption {
            filepath: None,
            comment: comment.to_string(),
        }
    }
}

impl fmt::Debug for DataCorruption {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        write!(f, "Data corruption")?;
        if let Some(ref filepath) = &self.filepath {
            write!(f, " (in file `{:?}`)", filepath)?;
        }
        write!(f, ": {}.", self.comment)?;
        Ok(())
    }
}

/// The library's error enum
#[derive(Debug, Error)]
pub enum TantivyError {
    /// Failed to open the directory.
    #[error("Failed to open the directory: '{0:?}'")]
    OpenDirectoryError(#[from] OpenDirectoryError),
    /// Failed to open a file for read.
    #[error("Failed to open file for read: '{0:?}'")]
    OpenReadError(#[from] OpenReadError),
    /// Failed to open a file for write.
    #[error("Failed to open file for write: '{0:?}'")]
    OpenWriteError(#[from] OpenWriteError),
    /// Index already exists in this directory.
    #[error("Index already exists")]
    IndexAlreadyExists,
    /// Failed to acquire file lock.
    #[error("Failed to acquire Lockfile: {0:?}. {1:?}")]
    LockFailure(LockError, Option<String>),
    /// IO Error.
    #[error("An IO error occurred: '{0}'")]
    IoError(#[from] io::Error),
    /// Data corruption.
    #[error("Data corrupted: '{0:?}'")]
    DataCorruption(DataCorruption),
    /// A thread holding the locked panicked and poisoned the lock.
    #[error("A thread holding the locked panicked and poisoned the lock")]
    Poisoned,
    /// The provided field name does not exist.
    #[error("The field does not exist: '{0}'")]
    FieldNotFound(String),
    /// Invalid argument was passed by the user.
    #[error("An invalid argument was passed: '{0}'")]
    InvalidArgument(String),
    /// An Error occurred in one of the threads.
    #[error("An error occurred in a thread: '{0}'")]
    ErrorInThread(String),
    /// An Error occurred related to opening or creating a index.
    #[error("Missing required index builder argument when open/create index: '{0}'")]
    IndexBuilderMissingArgument(&'static str),
    /// An Error occurred related to the schema.
    #[error("Schema error: '{0}'")]
    SchemaError(String),
    /// System error. (e.g.: We failed spawning a new thread).
    #[error("System error.'{0}'")]
    SystemError(String),
    /// Index incompatible with current version of Tantivy.
    #[error("{0:?}")]
    IncompatibleIndex(Incompatibility),
}

#[cfg(feature = "quickwit")]
#[derive(Error, Debug)]
#[doc(hidden)]
pub enum AsyncIoError {
    #[error("io::Error `{0}`")]
    Io(#[from] io::Error),
    #[error("Asynchronous API is unsupported by this directory")]
    AsyncUnsupported,
}

#[cfg(feature = "quickwit")]
impl From<AsyncIoError> for TantivyError {
    fn from(async_io_err: AsyncIoError) -> Self {
        match async_io_err {
            AsyncIoError::Io(io_err) => TantivyError::from(io_err),
            AsyncIoError::AsyncUnsupported => {
                TantivyError::SystemError(format!("{:?}", async_io_err))
            }
        }
    }
}

impl From<DataCorruption> for TantivyError {
    fn from(data_corruption: DataCorruption) -> TantivyError {
        TantivyError::DataCorruption(data_corruption)
    }
}
impl From<FastFieldNotAvailableError> for TantivyError {
    fn from(fastfield_error: FastFieldNotAvailableError) -> TantivyError {
        TantivyError::SchemaError(format!("{}", fastfield_error))
    }
}
impl From<LockError> for TantivyError {
    fn from(lock_error: LockError) -> TantivyError {
        TantivyError::LockFailure(lock_error, None)
    }
}

impl From<query::QueryParserError> for TantivyError {
    fn from(parsing_error: query::QueryParserError) -> TantivyError {
        TantivyError::InvalidArgument(format!("Query is invalid. {:?}", parsing_error))
    }
}

impl<Guard> From<PoisonError<Guard>> for TantivyError {
    fn from(_: PoisonError<Guard>) -> TantivyError {
        TantivyError::Poisoned
    }
}

impl From<chrono::ParseError> for TantivyError {
    fn from(err: chrono::ParseError) -> TantivyError {
        TantivyError::InvalidArgument(err.to_string())
    }
}

impl From<schema::DocParsingError> for TantivyError {
    fn from(error: schema::DocParsingError) -> TantivyError {
        TantivyError::InvalidArgument(format!("Failed to parse document {:?}", error))
    }
}

impl From<serde_json::Error> for TantivyError {
    fn from(error: serde_json::Error) -> TantivyError {
        TantivyError::IoError(error.into())
    }
}

impl From<rayon::ThreadPoolBuildError> for TantivyError {
    fn from(error: rayon::ThreadPoolBuildError) -> TantivyError {
        TantivyError::SystemError(error.to_string())
    }
}
<|endoftext|>


<commit_before>use rand;
use rand::Rng;
use std::collections::VecDeque;
use common::{ParamType, MoveDestination};
use piston_window::*;

pub enum Content {
    Number(u8),
    Mine(bool), // bool is true when this is the mine that caused you to loose the game.
    None,
}

struct Cell {
    content: Content,
    revealed: bool,
    marked: bool,
}

impl Cell {
    pub fn clear(&mut self) {
        self.content = Content::None;
        self.revealed = false;
        self.marked = false;
    }

    fn reveal(&mut self) -> &Content {
        self.revealed = true;
        &self.content
    }

    fn toggle_mark(&mut self) {
        self.marked = !self.marked;
    }
}

pub struct Field {
    cells: Vec<Cell>,
    width: u32,
    height: u32,
    mines: u32,
    size: u32,
    selected_x: u32,
    selected_y: u32,
    nubmers_total: u32,
    nubmers_opened: u32
}

impl Field {
    pub fn new(width: u32, height: u32, mines: u32) -> Field {
        let mut field = Field {
            width: width,
            height: height,
            cells: vec![],
            mines: mines,
            size: width*height,
            selected_x: width/2,
            selected_y: height/2,
            nubmers_total: 0,
            nubmers_opened: 0
        };
        field.reinit_vec();
        field.fill();
        field
    }

    fn reinit_vec(&mut self) {
        self.cells.clear();
        self.size = self.width*self.height;
        for _i in 0..self.size {
            self.cells.push(Cell{content: Content::None,
                                 revealed: false,
                                 marked: false});
        }
        self.selected_x = self.width/2;
        self.selected_y = self.height/2;
    }

    fn fill(&mut self) {
        self.clear();
        for _i in 0..self.mines {
            let ind = rand::thread_rng().gen_range(0, self.size);
            self.get_cell_mut(ind).content = Content::Mine(false);
        }
        let mut i: i32 = -1;
        let w = self.width as i32;
        while i < (self.size - 1) as i32 {
            i += 1;
            match self.get_content_safe(i) {
                Some(&Content::None) => {
                    let ct_mine = |b| {
                        match b {
                            true => 1,
                            false => 0
                        }
                    };
                     // don`t care about row
                    let mut ct = ct_mine(self.is_mine_safe(i-w)) +
                                 ct_mine(self.is_mine_safe(i+w));
                    if i % w > 0 { // check left side position
                        ct += ct_mine(self.is_mine_safe(i-w-1)) +
                              ct_mine(self.is_mine_safe(i-1)) +
                              ct_mine(self.is_mine_safe(i+w-1));
                    }
                    if i % w < w - 1 { // check right side position
                        ct += ct_mine(self.is_mine_safe(i-w+1)) +
                              ct_mine(self.is_mine_safe(i+1)) +
                              ct_mine(self.is_mine_safe(i+w+1));
                    }
                    if ct > 0 {
                        self.get_cell_mut(i as u32).content = Content::Number(ct);
                        self.nubmers_total += 1;
                    }
                },
                _ => {}
            }
        }
    }

    fn clear(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).clear();
        }
        self.nubmers_opened = 0;
        self.nubmers_total = 0;
    }

    pub fn reveal(&mut self, i: u32) -> &Content {
        if !self.revealed(i) {
            if let &Content::Number(_i) = self.get_cell_mut(i).reveal() {
                self.nubmers_opened += 1;
            }
        }
        &self.get_content(i)
    }

    pub fn revealed(&self, i: u32) -> bool {
        self.get_cell(i).revealed
    }

    pub fn marked(&self, i: u32) -> bool {
        self.get_cell(i).marked
    }

    pub fn set_killer(&mut self, i: u32) {
        self.get_cell_mut(i).content = Content::Mine(true);
    }

    fn get_cell_mut(&mut self, i:u32) -> &mut Cell {
        self.cells.get_mut(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell_mut ({})", i))
    }

    fn get_cell(& self, i:u32) -> &Cell {
        self.cells.get(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell ({})", i))
    }

    fn get_content_safe(&self, i:i32) -> Option<&Content> {
        if (i < 0) || ((i as u32) >= self.size) {
            None
        } else {
            Some(self.get_content(i as u32))
        }
    }

    pub fn get_content(& self, i: u32) -> &Content {
        &self.get_cell(i).content
    }

    fn is_mine_safe(&self, i: i32) -> bool {
        match self.get_content_safe(i) {
            Some(&Content::Mine(_)) => true,
            _ => false
        }
    }

    pub fn get_width(&self) -> u32 {
        self.width
    }

    pub fn get_height(&self) -> u32 {
        self.height
    }

    pub fn get_size(&self) -> u32 {
        self.size
    }

    pub fn restart(&mut self) {
        self.fill();
    }

    pub fn reveal_all(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).revealed = true;
        }
    }

    pub fn chain_reveal(&mut self, u: u32) {
        if self.marked(u) {
            return;
        }
        let w = self.width as i32;
        // clojure to check for blank cells
        let mut check = |x, d: &mut VecDeque<i32>| {
            match self.get_content_safe(x) {
                Some(&Content::None) => {
                    if !self.revealed(x as u32) {
                        d.push_back(x);
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                Some(&Content::Number(_n)) => {
                    if !(self.revealed(x as u32)) {
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                _ => {}
            }
        };
        // BFS initialize
        let deq = &mut VecDeque::new();
        deq.push_back(u as i32);
        // BFS
        while !deq.is_empty() {
            let i = deq.pop_front().unwrap();
            // don`t care about row
            check(i-w, deq);
            check(i+w, deq);
            if i % w > 0 { // check left side position
                check(i-w-1, deq);
                check(i-1, deq);
                check(i+w-1, deq);
            }
            if i % w < w - 1 { // check right side position
                check(i-w+1, deq);
                check(i+1, deq);
                check(i+w+1, deq);
            }
        }
    }

    pub fn draw(&mut self,
            context: Context,
            graphics: &mut G2d,
            field_rect: [u32; 4],
            glyps: &mut Glyphs)
    {
        let cell_w = field_rect[2] / self.get_width();
        let cell_h = field_rect[3] / self.get_height();
        for i in 0..self.get_width() {
            for j in 0..self.get_height() {
                let ind = i + j*self.get_width();
                let transform = context.transform.trans((field_rect[0] + i*cell_w) as f64 + 5.0,
                                                        (field_rect[1] + (j+1)*cell_h) as f64 - 5.0);
                if self.revealed(ind) {
                    match *self.get_content(i + j*self.get_width()) {
                        Content::Mine(killer) => {
                            rectangle([1.0, 0.0, 0.0, 1.0],
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                            if killer {
                                text::Text::colored([1.0, 1.0, 1.0, 1.0], cell_h).draw(
                                    "*",
                                    glyps,
                                    &context.draw_state,
                                    transform,
                                    graphics
                                );
                            }
                        },
                        Content::Number(n) => {
                            rectangle([1.0, 1.0, 1.0, 1.0],
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                            text::Text::colored([0.3, 0.3, 0.3, 1.0], cell_h).draw(
                                &*n.to_string(),
                                glyps,
                                &context.draw_state,
                                transform,
                                graphics
                            );
                        },
                        Content::None => {
                            rectangle([1.0, 1.0, 1.0, 1.0],
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                        }
                    }
                }
                if self.marked(ind) {
                    rectangle([0.0, 1.0, 0.0, 0.75],
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
            }
        }
        rectangle([0.5, 0.5, 0.5, 0.75],
                  [
                    (field_rect[0] + self.selected_x*cell_w) as f64,
                    (field_rect[1] + self.selected_y*cell_h) as f64,
                    cell_w as f64,
                    cell_h as f64
                  ],
                  context.transform,
                  graphics);
        for i in 0..self.get_width() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        (field_rect[0] + i*cell_w) as f64,
                        field_rect[1] as f64,
                        (field_rect[0] + i*cell_w) as f64,
                        (field_rect[1] + field_rect[3]) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
        for i in 0..self.get_height() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        field_rect[0] as f64,
                        (field_rect[1] + i*cell_h) as f64,
                        (field_rect[0] + field_rect[2]) as f64,
                        (field_rect[1] + i*cell_h) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
    }

    pub fn move_selection(&mut self, dest: MoveDestination) {
        match dest {
            MoveDestination::Up => {
                if self.selected_y > 0 {
                    self.selected_y -= 1;
                }
            },
            MoveDestination::Down => {
                if self.selected_y < self.height - 1 {
                    self.selected_y += 1;
                }
            },
            MoveDestination::Left => {
                if self.selected_x > 0 {
                    self.selected_x -= 1;
                }
            },
            MoveDestination::Right => {
                if self.selected_x < self.width - 1 {
                    self.selected_x += 1;
                }
            }
        }
    }

    pub fn get_selected_ind(&self) -> u32 {
        self.selected_x + self.selected_y*self.width
    }

    pub fn is_victory(&self) -> bool {
        self.nubmers_total == self.nubmers_opened
    }

    pub fn reinit_field(&mut self, num: u32, param: ParamType) {
        let mut restart_neded = false;
        match param {
            ParamType::Height => {
                if self.height != num {
                    self.height = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Width => {
                if self.width != num {
                    self.width = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Mines => {
                if self.mines != num {
                    self.mines = num;
                    restart_neded = true;
                }
            }
        }
        if restart_neded {
            self.restart();
        }
    }

    pub fn toggle_mark(&mut self, i: u32) {
        self.get_cell_mut(i).toggle_mark();
    }
}
<commit_msg>feat: colored numbers<commit_after>use rand;
use rand::Rng;
use std::collections::VecDeque;
use common::{ParamType, MoveDestination};
use piston_window::*;

pub enum Content {
    Number(u8),
    Mine(bool), // bool is true when this is the mine that caused you to loose the game.
    None,
}

struct Cell {
    content: Content,
    revealed: bool,
    marked: bool,
}

impl Cell {
    pub fn clear(&mut self) {
        self.content = Content::None;
        self.revealed = false;
        self.marked = false;
    }

    fn reveal(&mut self) -> &Content {
        self.revealed = true;
        &self.content
    }

    fn toggle_mark(&mut self) {
        self.marked = !self.marked;
    }
}

pub struct Field {
    cells: Vec<Cell>,
    width: u32,
    height: u32,
    mines: u32,
    size: u32,
    selected_x: u32,
    selected_y: u32,
    nubmers_total: u32,
    nubmers_opened: u32
}

impl Field {
    pub fn new(width: u32, height: u32, mines: u32) -> Field {
        let mut field = Field {
            width: width,
            height: height,
            cells: vec![],
            mines: mines,
            size: width*height,
            selected_x: width/2,
            selected_y: height/2,
            nubmers_total: 0,
            nubmers_opened: 0
        };
        field.reinit_vec();
        field.fill();
        field
    }

    fn reinit_vec(&mut self) {
        self.cells.clear();
        self.size = self.width*self.height;
        for _i in 0..self.size {
            self.cells.push(Cell{content: Content::None,
                                 revealed: false,
                                 marked: false});
        }
        self.selected_x = self.width/2;
        self.selected_y = self.height/2;
    }

    fn fill(&mut self) {
        self.clear();
        for _i in 0..self.mines {
            let ind = rand::thread_rng().gen_range(0, self.size);
            self.get_cell_mut(ind).content = Content::Mine(false);
        }
        let mut i: i32 = -1;
        let w = self.width as i32;
        while i < (self.size - 1) as i32 {
            i += 1;
            match self.get_content_safe(i) {
                Some(&Content::None) => {
                    let ct_mine = |b| {
                        match b {
                            true => 1,
                            false => 0
                        }
                    };
                     // don`t care about row
                    let mut ct = ct_mine(self.is_mine_safe(i-w)) +
                                 ct_mine(self.is_mine_safe(i+w));
                    if i % w > 0 { // check left side position
                        ct += ct_mine(self.is_mine_safe(i-w-1)) +
                              ct_mine(self.is_mine_safe(i-1)) +
                              ct_mine(self.is_mine_safe(i+w-1));
                    }
                    if i % w < w - 1 { // check right side position
                        ct += ct_mine(self.is_mine_safe(i-w+1)) +
                              ct_mine(self.is_mine_safe(i+1)) +
                              ct_mine(self.is_mine_safe(i+w+1));
                    }
                    if ct > 0 {
                        self.get_cell_mut(i as u32).content = Content::Number(ct);
                        self.nubmers_total += 1;
                    }
                },
                _ => {}
            }
        }
    }

    fn clear(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).clear();
        }
        self.nubmers_opened = 0;
        self.nubmers_total = 0;
    }

    pub fn reveal(&mut self, i: u32) -> &Content {
        if !self.revealed(i) {
            if let &Content::Number(_i) = self.get_cell_mut(i).reveal() {
                self.nubmers_opened += 1;
            }
        }
        &self.get_content(i)
    }

    pub fn revealed(&self, i: u32) -> bool {
        self.get_cell(i).revealed
    }

    pub fn marked(&self, i: u32) -> bool {
        self.get_cell(i).marked
    }

    pub fn set_killer(&mut self, i: u32) {
        self.get_cell_mut(i).content = Content::Mine(true);
    }

    fn get_cell_mut(&mut self, i:u32) -> &mut Cell {
        self.cells.get_mut(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell_mut ({})", i))
    }

    fn get_cell(& self, i:u32) -> &Cell {
        self.cells.get(i as usize)
            .unwrap_or_else(|| panic!("Range check error at Field::get_cell ({})", i))
    }

    fn get_content_safe(&self, i:i32) -> Option<&Content> {
        if (i < 0) || ((i as u32) >= self.size) {
            None
        } else {
            Some(self.get_content(i as u32))
        }
    }

    pub fn get_content(& self, i: u32) -> &Content {
        &self.get_cell(i).content
    }

    fn is_mine_safe(&self, i: i32) -> bool {
        match self.get_content_safe(i) {
            Some(&Content::Mine(_)) => true,
            _ => false
        }
    }

    pub fn get_width(&self) -> u32 {
        self.width
    }

    pub fn get_height(&self) -> u32 {
        self.height
    }

    pub fn get_size(&self) -> u32 {
        self.size
    }

    pub fn restart(&mut self) {
        self.fill();
    }

    pub fn reveal_all(&mut self) {
        for i in 0..self.size {
            self.get_cell_mut(i).revealed = true;
        }
    }

    pub fn chain_reveal(&mut self, u: u32) {
        if self.marked(u) {
            return;
        }
        let w = self.width as i32;
        // clojure to check for blank cells
        let mut check = |x, d: &mut VecDeque<i32>| {
            match self.get_content_safe(x) {
                Some(&Content::None) => {
                    if !self.revealed(x as u32) {
                        d.push_back(x);
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                Some(&Content::Number(_n)) => {
                    if !(self.revealed(x as u32)) {
                        self.get_cell_mut(x as u32).marked = false;
                        self.reveal(x as u32);
                    }
                },
                _ => {}
            }
        };
        // BFS initialize
        let deq = &mut VecDeque::new();
        deq.push_back(u as i32);
        // BFS
        while !deq.is_empty() {
            let i = deq.pop_front().unwrap();
            // don`t care about row
            check(i-w, deq);
            check(i+w, deq);
            if i % w > 0 { // check left side position
                check(i-w-1, deq);
                check(i-1, deq);
                check(i+w-1, deq);
            }
            if i % w < w - 1 { // check right side position
                check(i-w+1, deq);
                check(i+1, deq);
                check(i+w+1, deq);
            }
        }
    }

    pub fn draw(&mut self,
            context: Context,
            graphics: &mut G2d,
            field_rect: [u32; 4],
            glyps: &mut Glyphs)
    {
        let cell_w = field_rect[2] / self.get_width();
        let cell_h = field_rect[3] / self.get_height();
        for i in 0..self.get_width() {
            for j in 0..self.get_height() {
                let ind = i + j*self.get_width();
                let transform = context.transform.trans((field_rect[0] + i*cell_w) as f64 + 5.0,
                                                        (field_rect[1] + (j+1)*cell_h) as f64 - 5.0);
                if self.revealed(ind) {
                    match *self.get_content(i + j*self.get_width()) {
                        Content::Mine(killer) => {
                            rectangle([1.0, 0.0, 0.0, 1.0],
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                            if killer {
                                text::Text::colored([1.0, 1.0, 1.0, 1.0], cell_h).draw(
                                    "*",
                                    glyps,
                                    &context.draw_state,
                                    transform,
                                    graphics
                                );
                            }
                        },
                        Content::Number(n) => {
                            rectangle(color::hex("c0c0c0"),
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);

                            let text_color = match n {
                                1 => color::hex("0000ff"),
                                2 => color::hex("008000"),
                                3 => color::hex("ff0000"),
                                4 => color::hex("000080"),
                                5 => color::hex("800000"),
                                6 => color::hex("008080"),
                                7 => color::hex("000000"),
                                8 => color::hex("808080"),
                                _ => [0.0, 0.0, 0.0, 1.0]
                            };

                            text::Text::colored(text_color, cell_h).draw(
                                &*n.to_string(),
                                glyps,
                                &context.draw_state,
                                transform,
                                graphics
                            );
                        },
                        Content::None => {
                            rectangle(color::hex("c0c0c0"),
                                      [
                                        (field_rect[0] + i*cell_w) as f64,
                                        (field_rect[1] + j*cell_h) as f64,
                                        cell_w as f64,
                                        cell_h as f64
                                      ],
                                      context.transform,
                                      graphics);
                        }
                    }
                } else {
                    // non revealed
                    rectangle(color::hex("303030"),
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
                if self.marked(ind) {
                    rectangle([0.0, 1.0, 0.0, 0.75],
                              [
                                (field_rect[0] + i*cell_w) as f64,
                                (field_rect[1] + j*cell_h) as f64,
                                cell_w as f64,
                                cell_h as f64
                              ],
                              context.transform,
                              graphics);
                }
            }
        }
        rectangle([0.5, 0.5, 0.5, 0.75],
                  [
                    (field_rect[0] + self.selected_x*cell_w) as f64,
                    (field_rect[1] + self.selected_y*cell_h) as f64,
                    cell_w as f64,
                    cell_h as f64
                  ],
                  context.transform,
                  graphics);
        for i in 0..self.get_width() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        (field_rect[0] + i*cell_w) as f64,
                        field_rect[1] as f64,
                        (field_rect[0] + i*cell_w) as f64,
                        (field_rect[1] + field_rect[3]) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
        for i in 0..self.get_height() + 1 {
            line::Line::new([0.5, 0.5, 0.5, 1.0], 1.0)
                .draw([
                        field_rect[0] as f64,
                        (field_rect[1] + i*cell_h) as f64,
                        (field_rect[0] + field_rect[2]) as f64,
                        (field_rect[1] + i*cell_h) as f64
                      ],
                      &context.draw_state,
                      context.transform,
                      graphics);
        }
    }

    pub fn move_selection(&mut self, dest: MoveDestination) {
        match dest {
            MoveDestination::Up => {
                if self.selected_y > 0 {
                    self.selected_y -= 1;
                }
            },
            MoveDestination::Down => {
                if self.selected_y < self.height - 1 {
                    self.selected_y += 1;
                }
            },
            MoveDestination::Left => {
                if self.selected_x > 0 {
                    self.selected_x -= 1;
                }
            },
            MoveDestination::Right => {
                if self.selected_x < self.width - 1 {
                    self.selected_x += 1;
                }
            }
        }
    }

    pub fn get_selected_ind(&self) -> u32 {
        self.selected_x + self.selected_y*self.width
    }

    pub fn is_victory(&self) -> bool {
        self.nubmers_total == self.nubmers_opened
    }

    pub fn reinit_field(&mut self, num: u32, param: ParamType) {
        let mut restart_neded = false;
        match param {
            ParamType::Height => {
                if self.height != num {
                    self.height = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Width => {
                if self.width != num {
                    self.width = num;
                    self.reinit_vec();
                    restart_neded = true;
                }
            }
            ParamType::Mines => {
                if self.mines != num {
                    self.mines = num;
                    restart_neded = true;
                }
            }
        }
        if restart_neded {
            self.restart();
        }
    }

    pub fn toggle_mark(&mut self, i: u32) {
        self.get_cell_mut(i).toggle_mark();
    }
}
<|endoftext|>


<commit_before>use ::*;

#[derive(Copy, Clone)]
pub struct Tile {
    pub wall : Option<char>,
}

pub struct Floor {
    pub rows : usize,
    pub cols : usize,
    pub tiles : Vec<Vec<Tile>>
}

impl Floor {
    pub fn new(cols : usize, rows : usize) -> Self {
        // Tiles to use
        let horizontal   = Tile { wall : Some('─') }; // U-2500
        let vertical     = Tile { wall : Some('│') }; // U-2502
        let top_left     = Tile { wall : Some('┌') }; // U-250c
        let top_right    = Tile { wall : Some('┐') }; // U-2510
        let bottom_left  = Tile { wall : Some('└') }; // U-2514
        let bottom_right = Tile { wall : Some('┘') }; // U-2518
        let blank        = Tile { wall : None };

        // Create tiles 2D Vec and populate with empty rows
        let mut tiles = Vec::<Vec<Tile>>::with_capacity(rows);
        for _ in 0..rows {
            tiles.push(Vec::<Tile>::with_capacity(rows));
        }
        // First row is all wall
        tiles[0].push(top_left);
        for _ in 1..cols-1 {
            tiles[0].push(horizontal);
        }
        tiles[0].push(top_right);
        // Middle rows are vertical sides and blank middles
        for row in 1..rows-1 {
            tiles[row].push(vertical);
            for _ in 1..cols-1 {
                tiles[row].push(blank);
            }
            tiles[row].push(vertical);
        }
        // Bottom row is also all wall
        tiles[rows-1].push(bottom_left);
        for _ in 1..cols-1 {
            tiles[rows-1].push(horizontal);
        }
        tiles[rows-1].push(bottom_right);

        // Create the floor
        Self {
            rows : rows,
            cols : cols,
            tiles : tiles,
        }
    }
    pub fn get_symbol(&self, coord : &Coord) -> String {
        if let Some(wall) = self.tiles[coord.row as usize][coord.col as usize].wall {
            wall.to_string()
        } else {
            " ".to_string()
        }
    }
    pub fn is_wall(&self, coord : &Coord) -> bool {
        self.tiles[coord.row as usize][coord.col as usize].wall.is_some()
    }
}
<commit_msg>Be consistent with commas<commit_after>use ::*;

#[derive(Copy, Clone)]
pub struct Tile {
    pub wall : Option<char>,
}

pub struct Floor {
    pub rows : usize,
    pub cols : usize,
    pub tiles : Vec<Vec<Tile>>,
}

impl Floor {
    pub fn new(cols : usize, rows : usize) -> Self {
        // Tiles to use
        let horizontal   = Tile { wall : Some('─') }; // U-2500
        let vertical     = Tile { wall : Some('│') }; // U-2502
        let top_left     = Tile { wall : Some('┌') }; // U-250c
        let top_right    = Tile { wall : Some('┐') }; // U-2510
        let bottom_left  = Tile { wall : Some('└') }; // U-2514
        let bottom_right = Tile { wall : Some('┘') }; // U-2518
        let blank        = Tile { wall : None };

        // Create tiles 2D Vec and populate with empty rows
        let mut tiles = Vec::<Vec<Tile>>::with_capacity(rows);
        for _ in 0..rows {
            tiles.push(Vec::<Tile>::with_capacity(rows));
        }
        // First row is all wall
        tiles[0].push(top_left);
        for _ in 1..cols-1 {
            tiles[0].push(horizontal);
        }
        tiles[0].push(top_right);
        // Middle rows are vertical sides and blank middles
        for row in 1..rows-1 {
            tiles[row].push(vertical);
            for _ in 1..cols-1 {
                tiles[row].push(blank);
            }
            tiles[row].push(vertical);
        }
        // Bottom row is also all wall
        tiles[rows-1].push(bottom_left);
        for _ in 1..cols-1 {
            tiles[rows-1].push(horizontal);
        }
        tiles[rows-1].push(bottom_right);

        // Create the floor
        Self {
            rows : rows,
            cols : cols,
            tiles : tiles,
        }
    }
    pub fn get_symbol(&self, coord : &Coord) -> String {
        if let Some(wall) = self.tiles[coord.row as usize][coord.col as usize].wall {
            wall.to_string()
        } else {
            " ".to_string()
        }
    }
    pub fn is_wall(&self, coord : &Coord) -> bool {
        self.tiles[coord.row as usize][coord.col as usize].wall.is_some()
    }
}
<|endoftext|>