<commit_before>use std::{
    collections::HashMap,
    path::{Path, PathBuf},
};

use xshell::{cmd, read_file};

use crate::{
    cargo_files,
    codegen::{self, Mode},
    project_root, run_rustfmt, rust_files,
};

#[test]
fn generated_grammar_is_fresh() {
    if let Err(error) = codegen::generate_syntax(Mode::Verify) {
        panic!("{}. Please update it by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_tests_are_fresh() {
    if let Err(error) = codegen::generate_parser_tests(Mode::Verify) {
        panic!("{}. Please update tests by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_assists_are_fresh() {
    if let Err(error) = codegen::generate_assists_tests(Mode::Verify) {
        panic!("{}. Please update assists by running `cargo xtask codegen`", error);
    }
}

#[test]
fn check_code_formatting() {
    if let Err(error) = run_rustfmt(Mode::Verify) {
        panic!("{}. Please format the code by running `cargo format`", error);
    }
}

#[test]
fn smoke_test_docs_generation() {
    // We don't commit docs to the repo, so we can just overwrite in tests.
    codegen::generate_assists_docs(Mode::Overwrite).unwrap();
    codegen::generate_feature_docs(Mode::Overwrite).unwrap();
    codegen::generate_diagnostic_docs(Mode::Overwrite).unwrap();
}

#[test]
fn check_lsp_extensions_docs() {
    let expected_hash = {
        let lsp_ext_rs =
            read_file(project_root().join("crates/rust-analyzer/src/lsp_ext.rs")).unwrap();
        stable_hash(lsp_ext_rs.as_str())
    };

    let actual_hash = {
        let lsp_extensions_md =
            read_file(project_root().join("docs/dev/lsp-extensions.md")).unwrap();
        let text = lsp_extensions_md
            .lines()
            .find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
            .unwrap()
            .trim();
        u64::from_str_radix(text, 16).unwrap()
    };

    if actual_hash != expected_hash {
        panic!(
            "
lsp_ext.rs was changed without touching lsp-extensions.md.

Expected hash: {:x}
Actual hash:   {:x}

Please adjust docs/dev/lsp-extensions.md.
",
            expected_hash, actual_hash
        )
    }
}

#[test]
fn rust_files_are_tidy() {
    let mut tidy_docs = TidyDocs::default();
    for path in rust_files() {
        let text = read_file(&path).unwrap();
        check_todo(&path, &text);
        check_dbg(&path, &text);
        check_trailing_ws(&path, &text);
        deny_clippy(&path, &text);
        tidy_docs.visit(&path, &text);
    }
    tidy_docs.finish();
}

#[test]
fn cargo_files_are_tidy() {
    for cargo in cargo_files() {
        let mut section = None;
        for (line_no, text) in read_file(&cargo).unwrap().lines().enumerate() {
            let text = text.trim();
            if text.starts_with("[") {
                section = Some(text);
                continue;
            }
            if !section.map(|it| it.starts_with("[dependencies")).unwrap_or(false) {
                continue;
            }
            let text: String = text.split_whitespace().collect();
            if text.contains("path=") && !text.contains("version") {
                panic!(
                    "\ncargo internal dependencies should have version.\n\
                     {}:{}\n",
                    cargo.display(),
                    line_no + 1
                )
            }
        }
    }
}

#[test]
fn check_merge_commits() {
    let stdout = cmd!("git rev-list --merges --invert-grep --author 'bors\\[bot\\]' HEAD~19..")
        .read()
        .unwrap();
    if !stdout.is_empty() {
        panic!(
            "
Merge commits are not allowed in the history.

When updating a pull-request, please rebase your feature branch
on top of master by running `git rebase master`. If rebase fails,
you can re-apply your changes like this:

  # Just look around to see the current state.
  $ git status
  $ git log

  # Abort in-progress rebase and merges, if any.
  $ git rebase --abort
  $ git merge --abort

  # Make the branch point to the latest commit from master,
  # while maintaining your local changes uncommited.
  $ git reset --soft origin/master

  # Commit all changes in a single batch.
  $ git commit -am'My changes'

  # Verify that everything looks alright.
  $ git status
  $ git log

  # Push the changes. We did a rebase, so we need `--force` option.
  # `--force-with-lease` is a more safe (Rusty) version of `--force`.
  $ git push --force-with-lease

  # Verify that both local and remote branch point to the same commit.
  $ git log

And don't fear to mess something up during a rebase -- you can
always restore the previous state using `git ref-log`:

https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after-undo-local
"
        );
    }
}

fn deny_clippy(path: &PathBuf, text: &String) {
    let ignore = &[
        // The documentation in string literals may contain anything for its own purposes
        "ide_completion/src/generated_lint_completions.rs",
    ];
    if ignore.iter().any(|p| path.ends_with(p)) {
        return;
    }

    if text.contains("\u{61}llow(clippy") {
        panic!(
            "\n\nallowing lints is forbidden: {}.
rust-analyzer intentionally doesn't check clippy on CI.
You can allow lint globally via `xtask clippy`.
See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion.

",
            path.display()
        )
    }
}

#[test]
fn check_licenses() {
    let expected = "
0BSD OR MIT OR Apache-2.0
Apache-2.0
Apache-2.0 OR BSL-1.0
Apache-2.0 OR MIT
Apache-2.0/MIT
BSD-3-Clause
CC0-1.0
ISC
MIT
MIT / Apache-2.0
MIT OR Apache-2.0
MIT OR Apache-2.0 OR Zlib
MIT OR Zlib OR Apache-2.0
MIT/Apache-2.0
Unlicense OR MIT
Unlicense/MIT
Zlib OR Apache-2.0 OR MIT
"
    .lines()
    .filter(|it| !it.is_empty())
    .collect::<Vec<_>>();

    let meta = cmd!("cargo metadata --format-version 1").read().unwrap();
    let mut licenses = meta
        .split(|c| c == ',' || c == '{' || c == '}')
        .filter(|it| it.contains(r#""license""#))
        .map(|it| it.trim())
        .map(|it| it[r#""license":"#.len()..].trim_matches('"'))
        .collect::<Vec<_>>();
    licenses.sort();
    licenses.dedup();
    if licenses != expected {
        let mut diff = String::new();

        diff += &format!("New Licenses:\n");
        for &l in licenses.iter() {
            if !expected.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        diff += &format!("\nMissing Licenses:\n");
        for &l in expected.iter() {
            if !licenses.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        panic!("different set of licenses!\n{}", diff);
    }
    assert_eq!(licenses, expected);
}

fn check_todo(path: &Path, text: &str) {
    let need_todo = &[
        // This file itself obviously needs to use todo (<- like this!).
        "tests/tidy.rs",
        // Some of our assists generate `todo!()`.
        "handlers/add_turbo_fish.rs",
        "handlers/generate_function.rs",
        // To support generating `todo!()` in assists, we have `expr_todo()` in
        // `ast::make`.
        "ast/make.rs",
        // The documentation in string literals may contain anything for its own purposes
        "ide_completion/src/generated_lint_completions.rs",
    ];
    if need_todo.iter().any(|p| path.ends_with(p)) {
        return;
    }
    if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
        // Generated by an assist
        if text.contains("${0:todo!()}") {
            return;
        }

        panic!(
            "\nTODO markers or todo! macros should not be committed to the master branch,\n\
             use FIXME instead\n\
             {}\n",
            path.display(),
        )
    }
}

fn check_dbg(path: &Path, text: &str) {
    let need_dbg = &[
        // This file itself obviously needs to use dbg.
        "tests/tidy.rs",
        // Assists to remove `dbg!()`
        "handlers/remove_dbg.rs",
        // We have .dbg postfix
        "ide_completion/src/completions/postfix.rs",
        // The documentation in string literals may contain anything for its own purposes
        "ide_completion/src/lib.rs",
        "ide_completion/src/generated_lint_completions.rs",
        // test for doc test for remove_dbg
        "src/tests/generated.rs",
    ];
    if need_dbg.iter().any(|p| path.ends_with(p)) {
        return;
    }
    if text.contains("dbg!") {
        panic!(
            "\ndbg! macros should not be committed to the master branch,\n\
             {}\n",
            path.display(),
        )
    }
}

fn check_trailing_ws(path: &Path, text: &str) {
    if is_exclude_dir(path, &["test_data"]) {
        return;
    }
    for (line_number, line) in text.lines().enumerate() {
        if line.chars().last().map(char::is_whitespace) == Some(true) {
            panic!("Trailing whitespace in {} at line {}", path.display(), line_number)
        }
    }
}

#[derive(Default)]
struct TidyDocs {
    missing_docs: Vec<String>,
    contains_fixme: Vec<PathBuf>,
}

impl TidyDocs {
    fn visit(&mut self, path: &Path, text: &str) {
        // Test hopefully don't really need comments, and for assists we already
        // have special comments which are source of doc tests and user docs.
        if is_exclude_dir(path, &["tests", "test_data"]) {
            return;
        }

        if is_exclude_file(path) {
            return;
        }

        let first_line = match text.lines().next() {
            Some(it) => it,
            None => return,
        };

        if first_line.starts_with("//!") {
            if first_line.contains("FIXME") {
                self.contains_fixme.push(path.to_path_buf());
            }
        } else {
            if text.contains("// Feature:") || text.contains("// Assist:") {
                return;
            }
            self.missing_docs.push(path.display().to_string());
        }

        fn is_exclude_file(d: &Path) -> bool {
            let file_names = ["tests.rs", "famous_defs_fixture.rs"];

            d.file_name()
                .unwrap_or_default()
                .to_str()
                .map(|f_n| file_names.iter().any(|name| *name == f_n))
                .unwrap_or(false)
        }
    }

    fn finish(self) {
        if !self.missing_docs.is_empty() {
            panic!(
                "\nMissing docs strings\n\n\
                 modules:\n{}\n\n",
                self.missing_docs.join("\n")
            )
        }

        let poorly_documented = [
            "hir",
            "hir_expand",
            "ide",
            "mbe",
            "parser",
            "profile",
            "project_model",
            "syntax",
            "tt",
            "hir_ty",
        ];

        let mut has_fixmes =
            poorly_documented.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>();
        'outer: for path in self.contains_fixme {
            for krate in poorly_documented.iter() {
                if path.components().any(|it| it.as_os_str() == *krate) {
                    has_fixmes.insert(krate, true);
                    continue 'outer;
                }
            }
            panic!("FIXME doc in a fully-documented crate: {}", path.display())
        }

        for (krate, has_fixme) in has_fixmes.iter() {
            if !has_fixme {
                panic!("crate {} is fully documented :tada:, remove it from the list of poorly documented crates", krate)
            }
        }
    }
}

fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool {
    p.strip_prefix(project_root())
        .unwrap()
        .components()
        .rev()
        .skip(1)
        .filter_map(|it| it.as_os_str().to_str())
        .any(|it| dirs_to_exclude.contains(&it))
}

#[allow(deprecated)]
fn stable_hash(text: &str) -> u64 {
    use std::hash::{Hash, Hasher, SipHasher};

    let text = text.replace('\r', "");
    let mut hasher = SipHasher::default();
    text.hash(&mut hasher);
    hasher.finish()
}
<commit_msg>Check for path dev-dependencies with a version number<commit_after>use std::{
    collections::HashMap,
    path::{Path, PathBuf},
};

use xshell::{cmd, read_file};

use crate::{
    cargo_files,
    codegen::{self, Mode},
    project_root, run_rustfmt, rust_files,
};

#[test]
fn generated_grammar_is_fresh() {
    if let Err(error) = codegen::generate_syntax(Mode::Verify) {
        panic!("{}. Please update it by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_tests_are_fresh() {
    if let Err(error) = codegen::generate_parser_tests(Mode::Verify) {
        panic!("{}. Please update tests by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_assists_are_fresh() {
    if let Err(error) = codegen::generate_assists_tests(Mode::Verify) {
        panic!("{}. Please update assists by running `cargo xtask codegen`", error);
    }
}

#[test]
fn check_code_formatting() {
    if let Err(error) = run_rustfmt(Mode::Verify) {
        panic!("{}. Please format the code by running `cargo format`", error);
    }
}

#[test]
fn smoke_test_docs_generation() {
    // We don't commit docs to the repo, so we can just overwrite in tests.
    codegen::generate_assists_docs(Mode::Overwrite).unwrap();
    codegen::generate_feature_docs(Mode::Overwrite).unwrap();
    codegen::generate_diagnostic_docs(Mode::Overwrite).unwrap();
}

#[test]
fn check_lsp_extensions_docs() {
    let expected_hash = {
        let lsp_ext_rs =
            read_file(project_root().join("crates/rust-analyzer/src/lsp_ext.rs")).unwrap();
        stable_hash(lsp_ext_rs.as_str())
    };

    let actual_hash = {
        let lsp_extensions_md =
            read_file(project_root().join("docs/dev/lsp-extensions.md")).unwrap();
        let text = lsp_extensions_md
            .lines()
            .find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
            .unwrap()
            .trim();
        u64::from_str_radix(text, 16).unwrap()
    };

    if actual_hash != expected_hash {
        panic!(
            "
lsp_ext.rs was changed without touching lsp-extensions.md.

Expected hash: {:x}
Actual hash:   {:x}

Please adjust docs/dev/lsp-extensions.md.
",
            expected_hash, actual_hash
        )
    }
}

#[test]
fn rust_files_are_tidy() {
    let mut tidy_docs = TidyDocs::default();
    for path in rust_files() {
        let text = read_file(&path).unwrap();
        check_todo(&path, &text);
        check_dbg(&path, &text);
        check_trailing_ws(&path, &text);
        deny_clippy(&path, &text);
        tidy_docs.visit(&path, &text);
    }
    tidy_docs.finish();
}

#[test]
fn cargo_files_are_tidy() {
    for cargo in cargo_files() {
        let mut section = None;
        for (line_no, text) in read_file(&cargo).unwrap().lines().enumerate() {
            let text = text.trim();
            if text.starts_with('[') {
                if !text.ends_with(']') {
                    panic!(
                        "\nplease don't add comments or trailing whitespace in section lines.\n\
                            {}:{}\n",
                        cargo.display(),
                        line_no + 1
                    )
                }
                section = Some(text);
                continue;
            }
            let text: String = text.split_whitespace().collect();
            if !text.contains("path=") {
                continue;
            }
            match section {
                Some(s) if s.contains("dev-dependencies") => {
                    if text.contains("version") {
                        panic!(
                            "\ncargo internal dev-dependencies should not have a version.\n\
                            {}:{}\n",
                            cargo.display(),
                            line_no + 1
                        );
                    }
                }
                Some(s) if s.contains("dependencies") => {
                    if !text.contains("version") {
                        panic!(
                            "\ncargo internal dependencies should have a version.\n\
                            {}:{}\n",
                            cargo.display(),
                            line_no + 1
                        );
                    }
                }
                _ => {}
            }
        }
    }
}

#[test]
fn check_merge_commits() {
    let stdout = cmd!("git rev-list --merges --invert-grep --author 'bors\\[bot\\]' HEAD~19..")
        .read()
        .unwrap();
    if !stdout.is_empty() {
        panic!(
            "
Merge commits are not allowed in the history.

When updating a pull-request, please rebase your feature branch
on top of master by running `git rebase master`. If rebase fails,
you can re-apply your changes like this:

  # Just look around to see the current state.
  $ git status
  $ git log

  # Abort in-progress rebase and merges, if any.
  $ git rebase --abort
  $ git merge --abort

  # Make the branch point to the latest commit from master,
  # while maintaining your local changes uncommited.
  $ git reset --soft origin/master

  # Commit all changes in a single batch.
  $ git commit -am'My changes'

  # Verify that everything looks alright.
  $ git status
  $ git log

  # Push the changes. We did a rebase, so we need `--force` option.
  # `--force-with-lease` is a more safe (Rusty) version of `--force`.
  $ git push --force-with-lease

  # Verify that both local and remote branch point to the same commit.
  $ git log

And don't fear to mess something up during a rebase -- you can
always restore the previous state using `git ref-log`:

https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after-undo-local
"
        );
    }
}

fn deny_clippy(path: &PathBuf, text: &String) {
    let ignore = &[
        // The documentation in string literals may contain anything for its own purposes
        "ide_completion/src/generated_lint_completions.rs",
    ];
    if ignore.iter().any(|p| path.ends_with(p)) {
        return;
    }

    if text.contains("\u{61}llow(clippy") {
        panic!(
            "\n\nallowing lints is forbidden: {}.
rust-analyzer intentionally doesn't check clippy on CI.
You can allow lint globally via `xtask clippy`.
See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion.

",
            path.display()
        )
    }
}

#[test]
fn check_licenses() {
    let expected = "
0BSD OR MIT OR Apache-2.0
Apache-2.0
Apache-2.0 OR BSL-1.0
Apache-2.0 OR MIT
Apache-2.0/MIT
BSD-3-Clause
CC0-1.0
ISC
MIT
MIT / Apache-2.0
MIT OR Apache-2.0
MIT OR Apache-2.0 OR Zlib
MIT OR Zlib OR Apache-2.0
MIT/Apache-2.0
Unlicense OR MIT
Unlicense/MIT
Zlib OR Apache-2.0 OR MIT
"
    .lines()
    .filter(|it| !it.is_empty())
    .collect::<Vec<_>>();

    let meta = cmd!("cargo metadata --format-version 1").read().unwrap();
    let mut licenses = meta
        .split(|c| c == ',' || c == '{' || c == '}')
        .filter(|it| it.contains(r#""license""#))
        .map(|it| it.trim())
        .map(|it| it[r#""license":"#.len()..].trim_matches('"'))
        .collect::<Vec<_>>();
    licenses.sort();
    licenses.dedup();
    if licenses != expected {
        let mut diff = String::new();

        diff += &format!("New Licenses:\n");
        for &l in licenses.iter() {
            if !expected.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        diff += &format!("\nMissing Licenses:\n");
        for &l in expected.iter() {
            if !licenses.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        panic!("different set of licenses!\n{}", diff);
    }
    assert_eq!(licenses, expected);
}

fn check_todo(path: &Path, text: &str) {
    let need_todo = &[
        // This file itself obviously needs to use todo (<- like this!).
        "tests/tidy.rs",
        // Some of our assists generate `todo!()`.
        "handlers/add_turbo_fish.rs",
        "handlers/generate_function.rs",
        // To support generating `todo!()` in assists, we have `expr_todo()` in
        // `ast::make`.
        "ast/make.rs",
        // The documentation in string literals may contain anything for its own purposes
        "ide_completion/src/generated_lint_completions.rs",
    ];
    if need_todo.iter().any(|p| path.ends_with(p)) {
        return;
    }
    if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
        // Generated by an assist
        if text.contains("${0:todo!()}") {
            return;
        }

        panic!(
            "\nTODO markers or todo! macros should not be committed to the master branch,\n\
             use FIXME instead\n\
             {}\n",
            path.display(),
        )
    }
}

fn check_dbg(path: &Path, text: &str) {
    let need_dbg = &[
        // This file itself obviously needs to use dbg.
        "tests/tidy.rs",
        // Assists to remove `dbg!()`
        "handlers/remove_dbg.rs",
        // We have .dbg postfix
        "ide_completion/src/completions/postfix.rs",
        // The documentation in string literals may contain anything for its own purposes
        "ide_completion/src/lib.rs",
        "ide_completion/src/generated_lint_completions.rs",
        // test for doc test for remove_dbg
        "src/tests/generated.rs",
    ];
    if need_dbg.iter().any(|p| path.ends_with(p)) {
        return;
    }
    if text.contains("dbg!") {
        panic!(
            "\ndbg! macros should not be committed to the master branch,\n\
             {}\n",
            path.display(),
        )
    }
}

fn check_trailing_ws(path: &Path, text: &str) {
    if is_exclude_dir(path, &["test_data"]) {
        return;
    }
    for (line_number, line) in text.lines().enumerate() {
        if line.chars().last().map(char::is_whitespace) == Some(true) {
            panic!("Trailing whitespace in {} at line {}", path.display(), line_number)
        }
    }
}

#[derive(Default)]
struct TidyDocs {
    missing_docs: Vec<String>,
    contains_fixme: Vec<PathBuf>,
}

impl TidyDocs {
    fn visit(&mut self, path: &Path, text: &str) {
        // Test hopefully don't really need comments, and for assists we already
        // have special comments which are source of doc tests and user docs.
        if is_exclude_dir(path, &["tests", "test_data"]) {
            return;
        }

        if is_exclude_file(path) {
            return;
        }

        let first_line = match text.lines().next() {
            Some(it) => it,
            None => return,
        };

        if first_line.starts_with("//!") {
            if first_line.contains("FIXME") {
                self.contains_fixme.push(path.to_path_buf());
            }
        } else {
            if text.contains("// Feature:") || text.contains("// Assist:") {
                return;
            }
            self.missing_docs.push(path.display().to_string());
        }

        fn is_exclude_file(d: &Path) -> bool {
            let file_names = ["tests.rs", "famous_defs_fixture.rs"];

            d.file_name()
                .unwrap_or_default()
                .to_str()
                .map(|f_n| file_names.iter().any(|name| *name == f_n))
                .unwrap_or(false)
        }
    }

    fn finish(self) {
        if !self.missing_docs.is_empty() {
            panic!(
                "\nMissing docs strings\n\n\
                 modules:\n{}\n\n",
                self.missing_docs.join("\n")
            )
        }

        let poorly_documented = [
            "hir",
            "hir_expand",
            "ide",
            "mbe",
            "parser",
            "profile",
            "project_model",
            "syntax",
            "tt",
            "hir_ty",
        ];

        let mut has_fixmes =
            poorly_documented.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>();
        'outer: for path in self.contains_fixme {
            for krate in poorly_documented.iter() {
                if path.components().any(|it| it.as_os_str() == *krate) {
                    has_fixmes.insert(krate, true);
                    continue 'outer;
                }
            }
            panic!("FIXME doc in a fully-documented crate: {}", path.display())
        }

        for (krate, has_fixme) in has_fixmes.iter() {
            if !has_fixme {
                panic!("crate {} is fully documented :tada:, remove it from the list of poorly documented crates", krate)
            }
        }
    }
}

fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool {
    p.strip_prefix(project_root())
        .unwrap()
        .components()
        .rev()
        .skip(1)
        .filter_map(|it| it.as_os_str().to_str())
        .any(|it| dirs_to_exclude.contains(&it))
}

#[allow(deprecated)]
fn stable_hash(text: &str) -> u64 {
    use std::hash::{Hash, Hasher, SipHasher};

    let text = text.replace('\r', "");
    let mut hasher = SipHasher::default();
    text.hash(&mut hasher);
    hasher.finish()
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::chained_bft::{common::Round, consensus_types::vote_data::VoteData};
use crypto::{
    hash::{CryptoHash, ACCUMULATOR_PLACEHOLDER_HASH, GENESIS_BLOCK_ID},
    HashValue,
};
use failure::{Result, ResultExt};
use network::proto::QuorumCert as ProtoQuorumCert;
use proto_conv::{FromProto, IntoProto};
use serde::{Deserialize, Serialize};
use std::{
    collections::HashMap,
    fmt::{Display, Formatter},
};
use types::{
    crypto_proxies::{LedgerInfoWithSignatures, ValidatorSigner, ValidatorVerifier},
    ledger_info::LedgerInfo,
};

#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)]
pub struct QuorumCert {
    /// The vote information certified by the quorum.
    vote_data: VoteData,
    /// The signed LedgerInfo of a committed block that carries the data about the certified block.
    signed_ledger_info: LedgerInfoWithSignatures,
}

impl Display for QuorumCert {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(
            f,
            "QuorumCert: [{}, {}]",
            self.vote_data, self.signed_ledger_info
        )
    }
}

impl QuorumCert {
    pub fn new(vote_data: VoteData, signed_ledger_info: LedgerInfoWithSignatures) -> Self {
        QuorumCert {
            vote_data,
            signed_ledger_info,
        }
    }
    /// All the vote data getters are just proxies for retrieving the values from the VoteData
    pub fn certified_block_id(&self) -> HashValue {
        self.vote_data.block_id()
    }

    pub fn certified_state_id(&self) -> HashValue {
        self.vote_data.executed_state_id()
    }

    pub fn certified_block_round(&self) -> Round {
        self.vote_data.block_round()
    }

    pub fn parent_block_id(&self) -> HashValue {
        self.vote_data.parent_block_id()
    }

    pub fn parent_block_round(&self) -> Round {
        self.vote_data.parent_block_round()
    }

    pub fn grandparent_block_id(&self) -> HashValue {
        self.vote_data.grandparent_block_id()
    }
    pub fn grandparent_block_round(&self) -> Round {
        self.vote_data.grandparent_block_round()
    }

    pub fn ledger_info(&self) -> &LedgerInfoWithSignatures {
        &self.signed_ledger_info
    }

    pub fn committed_block_id(&self) -> Option<HashValue> {
        let id = self.ledger_info().ledger_info().consensus_block_id();
        if id.is_zero() {
            None
        } else {
            Some(id)
        }
    }

    /// QuorumCert for the genesis block:
    /// - the ID of the block is predetermined by the `GENESIS_BLOCK_ID` constant.
    /// - the accumulator root hash of the LedgerInfo is set to `ACCUMULATOR_PLACEHOLDER_HASH`
    ///   constant.
    /// - the map of signatures is empty because genesis block is implicitly agreed.
    pub fn certificate_for_genesis() -> QuorumCert {
        let genesis_digest = VoteData::vote_digest(
            *GENESIS_BLOCK_ID,
            *ACCUMULATOR_PLACEHOLDER_HASH,
            0,
            *GENESIS_BLOCK_ID,
            0,
            *GENESIS_BLOCK_ID,
            0,
        );
        let signer = ValidatorSigner::genesis();
        let li = LedgerInfo::new(
            0,
            *ACCUMULATOR_PLACEHOLDER_HASH,
            genesis_digest,
            *GENESIS_BLOCK_ID,
            0,
            0,
            None,
        );
        let signature = signer
            .sign_message(li.hash())
            .expect("Fail to sign genesis ledger info");
        let mut signatures = HashMap::new();
        signatures.insert(signer.author(), signature);
        QuorumCert::new(
            VoteData::new(
                *GENESIS_BLOCK_ID,
                *ACCUMULATOR_PLACEHOLDER_HASH,
                0,
                *GENESIS_BLOCK_ID,
                0,
                *GENESIS_BLOCK_ID,
                0,
            ),
            LedgerInfoWithSignatures::new(li, signatures),
        )
    }

    pub fn verify(&self, validator: &ValidatorVerifier) -> failure::Result<()> {
        let vote_hash = self.vote_data.hash();
        ensure!(
            self.ledger_info().ledger_info().consensus_data_hash() == vote_hash,
            "Quorum Cert's hash mismatch LedgerInfo"
        );
        // Genesis is implicitly agreed upon, it doesn't have real signatures.
        if self.vote_data.block_round() == 0
            && self.vote_data.block_id() == *GENESIS_BLOCK_ID
            && self.vote_data.executed_state_id() == *ACCUMULATOR_PLACEHOLDER_HASH
        {
            return Ok(());
        }
        self.ledger_info()
            .verify(validator)
            .with_context(|e| format!("Fail to verify QuorumCert: {:?}", e))?;
        Ok(())
    }
}

impl IntoProto for QuorumCert {
    type ProtoType = ProtoQuorumCert;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        proto.set_vote_data(self.vote_data.into_proto());
        proto.set_signed_ledger_info(self.signed_ledger_info.into_proto());
        proto
    }
}

impl FromProto for QuorumCert {
    type ProtoType = ProtoQuorumCert;

    fn from_proto(mut object: Self::ProtoType) -> Result<Self> {
        let vote_data = VoteData::from_proto(object.take_vote_data())?;
        let signed_ledger_info =
            LedgerInfoWithSignatures::from_proto(object.take_signed_ledger_info())?;

        Ok(QuorumCert {
            vote_data,
            signed_ledger_info,
        })
    }
}
<commit_msg>[consensus] impl conversions from/to prost proto and QuorumCert<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::chained_bft::{common::Round, consensus_types::vote_data::VoteData};
use crypto::{
    hash::{CryptoHash, ACCUMULATOR_PLACEHOLDER_HASH, GENESIS_BLOCK_ID},
    HashValue,
};
use failure::{Result, ResultExt};
use network::proto::QuorumCert as ProtoQuorumCert;
use proto_conv::{FromProto, IntoProto};
use serde::{Deserialize, Serialize};
use std::{
    collections::HashMap,
    convert::{TryFrom, TryInto},
    fmt::{Display, Formatter},
};
use types::{
    crypto_proxies::{LedgerInfoWithSignatures, ValidatorSigner, ValidatorVerifier},
    ledger_info::LedgerInfo,
};

#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)]
pub struct QuorumCert {
    /// The vote information certified by the quorum.
    vote_data: VoteData,
    /// The signed LedgerInfo of a committed block that carries the data about the certified block.
    signed_ledger_info: LedgerInfoWithSignatures,
}

impl Display for QuorumCert {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(
            f,
            "QuorumCert: [{}, {}]",
            self.vote_data, self.signed_ledger_info
        )
    }
}

impl QuorumCert {
    pub fn new(vote_data: VoteData, signed_ledger_info: LedgerInfoWithSignatures) -> Self {
        QuorumCert {
            vote_data,
            signed_ledger_info,
        }
    }
    /// All the vote data getters are just proxies for retrieving the values from the VoteData
    pub fn certified_block_id(&self) -> HashValue {
        self.vote_data.block_id()
    }

    pub fn certified_state_id(&self) -> HashValue {
        self.vote_data.executed_state_id()
    }

    pub fn certified_block_round(&self) -> Round {
        self.vote_data.block_round()
    }

    pub fn parent_block_id(&self) -> HashValue {
        self.vote_data.parent_block_id()
    }

    pub fn parent_block_round(&self) -> Round {
        self.vote_data.parent_block_round()
    }

    pub fn grandparent_block_id(&self) -> HashValue {
        self.vote_data.grandparent_block_id()
    }
    pub fn grandparent_block_round(&self) -> Round {
        self.vote_data.grandparent_block_round()
    }

    pub fn ledger_info(&self) -> &LedgerInfoWithSignatures {
        &self.signed_ledger_info
    }

    pub fn committed_block_id(&self) -> Option<HashValue> {
        let id = self.ledger_info().ledger_info().consensus_block_id();
        if id.is_zero() {
            None
        } else {
            Some(id)
        }
    }

    /// QuorumCert for the genesis block:
    /// - the ID of the block is predetermined by the `GENESIS_BLOCK_ID` constant.
    /// - the accumulator root hash of the LedgerInfo is set to `ACCUMULATOR_PLACEHOLDER_HASH`
    ///   constant.
    /// - the map of signatures is empty because genesis block is implicitly agreed.
    pub fn certificate_for_genesis() -> QuorumCert {
        let genesis_digest = VoteData::vote_digest(
            *GENESIS_BLOCK_ID,
            *ACCUMULATOR_PLACEHOLDER_HASH,
            0,
            *GENESIS_BLOCK_ID,
            0,
            *GENESIS_BLOCK_ID,
            0,
        );
        let signer = ValidatorSigner::genesis();
        let li = LedgerInfo::new(
            0,
            *ACCUMULATOR_PLACEHOLDER_HASH,
            genesis_digest,
            *GENESIS_BLOCK_ID,
            0,
            0,
            None,
        );
        let signature = signer
            .sign_message(li.hash())
            .expect("Fail to sign genesis ledger info");
        let mut signatures = HashMap::new();
        signatures.insert(signer.author(), signature);
        QuorumCert::new(
            VoteData::new(
                *GENESIS_BLOCK_ID,
                *ACCUMULATOR_PLACEHOLDER_HASH,
                0,
                *GENESIS_BLOCK_ID,
                0,
                *GENESIS_BLOCK_ID,
                0,
            ),
            LedgerInfoWithSignatures::new(li, signatures),
        )
    }

    pub fn verify(&self, validator: &ValidatorVerifier) -> failure::Result<()> {
        let vote_hash = self.vote_data.hash();
        ensure!(
            self.ledger_info().ledger_info().consensus_data_hash() == vote_hash,
            "Quorum Cert's hash mismatch LedgerInfo"
        );
        // Genesis is implicitly agreed upon, it doesn't have real signatures.
        if self.vote_data.block_round() == 0
            && self.vote_data.block_id() == *GENESIS_BLOCK_ID
            && self.vote_data.executed_state_id() == *ACCUMULATOR_PLACEHOLDER_HASH
        {
            return Ok(());
        }
        self.ledger_info()
            .verify(validator)
            .with_context(|e| format!("Fail to verify QuorumCert: {:?}", e))?;
        Ok(())
    }
}

impl IntoProto for QuorumCert {
    type ProtoType = ProtoQuorumCert;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        proto.set_vote_data(self.vote_data.into_proto());
        proto.set_signed_ledger_info(self.signed_ledger_info.into_proto());
        proto
    }
}

impl FromProto for QuorumCert {
    type ProtoType = ProtoQuorumCert;

    fn from_proto(mut object: Self::ProtoType) -> Result<Self> {
        let vote_data = VoteData::from_proto(object.take_vote_data())?;
        let signed_ledger_info =
            LedgerInfoWithSignatures::from_proto(object.take_signed_ledger_info())?;

        Ok(QuorumCert {
            vote_data,
            signed_ledger_info,
        })
    }
}

impl TryFrom<network::proto::consensus_prost::QuorumCert> for QuorumCert {
    type Error = failure::Error;

    fn try_from(proto: network::proto::consensus_prost::QuorumCert) -> failure::Result<Self> {
        let vote_data = proto
            .vote_data
            .ok_or_else(|| format_err!("Missing vote_data"))?
            .try_into()?;
        let signed_ledger_info = proto
            .signed_ledger_info
            .ok_or_else(|| format_err!("Missing signed_ledger_info"))?
            .try_into()?;

        Ok(QuorumCert {
            vote_data,
            signed_ledger_info,
        })
    }
}

impl From<QuorumCert> for network::proto::consensus_prost::QuorumCert {
    fn from(cert: QuorumCert) -> Self {
        Self {
            vote_data: Some(cert.vote_data.into()),
            signed_ledger_info: Some(cert.signed_ledger_info.into()),
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>docs(complete): Don't use deprecated API<commit_after><|endoftext|>


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

pub struct Translator
{
	rules: HashMap<(char, char), char>,
}

impl Translator
{
	pub fn new() -> Translator
	{
		Translator
		{
			rules: get_default_rules(),
		}
	}

	fn translate_char(&self, current : char, previous : char) -> char
	{
		match self.rules.get(&(current, previous))
		{
			Some(result) => *result,
			None => match self.rules.get(&(current, ' '))
			{
				Some(result) => *result,
				None => current,
			}
		}
	}

	pub fn translate(&self, text : &str) -> String
	{
		let mut result = String::with_capacity(text.len());

		let mut previous = ' ';
		for c in text.chars()
		{
			previous = self.translate_char(c, previous);
			result.push(previous);
		}

		result
	}
}

fn get_default_rules() -> HashMap<(char, char), char>
{
	let mut result = HashMap::with_capacity(50);

	result.insert(('A', ' '), 'А');
	result.insert(('a', ' '), 'а');
	result.insert(('B', ' '), 'Б');
	result.insert(('b', ' '), 'б');
	result.insert(('V', ' '), 'В');
	result.insert(('v', ' '), 'в');
	result.insert(('G', ' '), 'Г');
	result.insert(('g', ' '), 'г');
	result.insert(('D', ' '), 'Д');
	result.insert(('d', ' '), 'д');
	result.insert(('E', ' '), 'Е');
	result.insert(('e', ' '), 'е');
	result.insert(('O', 'J'), 'Ё');
	result.insert(('O', 'Й'), 'Ё');
	result.insert(('o', 'j'), 'ё');
	result.insert(('o', 'й'), 'ё');
	result.insert(('H', 'Z'), 'Ж');
	result.insert(('H', 'З'), 'Ж');
	result.insert(('h', 'z'), 'ж');
	result.insert(('h', 'з'), 'ж');
	result.insert(('Z', ' '), 'З');
	result.insert(('z', ' '), 'з');
	result.insert(('I', ' '), 'И');
	result.insert(('i', ' '), 'и');
	result.insert(('J', ' '), 'Й');
	result.insert(('j', ' '), 'й');
	result.insert(('K', ' '), 'К');
	result.insert(('k', ' '), 'к');
	result.insert(('L', ' '), 'Л');
	result.insert(('l', ' '), 'л');
	result.insert(('M', ' '), 'М');
	result.insert(('m', ' '), 'м');
	result.insert(('N', ' '), 'Н');
	result.insert(('n', ' '), 'н');
	result.insert(('O', ' '), 'О');
	result.insert(('o', ' '), 'о');
	result.insert(('P', ' '), 'П');
	result.insert(('p', ' '), 'п');
	result.insert(('R', ' '), 'Р');
	result.insert(('r', ' '), 'р');
	result.insert(('S', ' '), 'С');
	result.insert(('s', ' '), 'с');
	result.insert(('T', ' '), 'Т');
	result.insert(('t', ' '), 'т');
	result.insert(('U', ' '), 'У');
	result.insert(('u', ' '), 'у');
	result.insert(('F', ' '), 'Ф');
	result.insert(('f', ' '), 'ф');
	result.insert(('H', ' '), 'Х');
	result.insert(('X', ' '), 'Х');
	result.insert(('h', ' '), 'х');
	result.insert(('x', ' '), 'х');
	result.insert(('C', ' '), 'Ц');
	result.insert(('c', ' '), 'ц');
	result.insert(('H', 'C'), 'Ч');
	result.insert(('H', 'Ц'), 'Ч');
	result.insert(('h', 'c'), 'ч');
	result.insert(('h', 'ц'), 'ч');
	result.insert(('H', 'H'), 'Ш');
	result.insert(('H', 'С'), 'Ш');
	result.insert(('h', 'h'), 'ш');
	result.insert(('h', 'с'), 'ш');
	result.insert(('H', 'Ш'), 'Щ');
	result.insert(('W', ' '), 'Щ');
	result.insert(('h', 'ш'), 'щ');
	result.insert(('w', ' '), 'щ');
	result.insert(('#', 'ъ'), 'Ъ');
	result.insert(('#', ' '), 'ъ');
	result.insert(('Y', ' '), 'Ы');
	result.insert(('y', ' '), 'ы');
	result.insert(('\'', 'ь'), 'Ь');
	result.insert(('\'', ' '), 'ь');
	result.insert(('E', 'J'), 'Э');
	result.insert(('E', 'Й'), 'Э');
	result.insert(('e', 'j'), 'э');
	result.insert(('e', 'й'), 'э');
	result.insert(('U', 'J'), 'Ю');
	result.insert(('U', 'Й'), 'Ю');
	result.insert(('u', 'j'), 'ю');
	result.insert(('u', 'й'), 'ю');
	result.insert(('A', 'J'), 'Я');
	result.insert(('A', 'Й'), 'Я');
	result.insert(('a', 'j'), 'я');
	result.insert(('a', 'й'), 'я');

	result
}
<commit_msg>Translation rules organization<commit_after>use std::collections::HashMap;

pub struct Translator
{
	rules: HashMap<(char, char), char>,
}

impl Translator
{
	pub fn new() -> Translator
	{
		Translator
		{
			rules: get_default_rules(),
		}
	}

	fn translate_char(&self, current : char, previous : char) -> char
	{
		match self.rules.get(&(current, previous))
		{
			Some(result) => *result,
			None => match self.rules.get(&(current, ' '))
			{
				Some(result) => *result,
				None => current,
			}
		}
	}

	pub fn translate(&self, text : &str) -> String
	{
		let mut result = String::with_capacity(text.len());

		let mut previous = ' ';
		for c in text.chars()
		{
			previous = self.translate_char(c, previous);
			result.push(previous);
		}

		result
	}
}

fn get_default_rules() -> HashMap<(char, char), char>
{
	let mut result = HashMap::with_capacity(50);

	result.insert(('a', ' '), 'а');
	result.insert(('b', ' '), 'б');
	result.insert(('v', ' '), 'в');
	result.insert(('g', ' '), 'г');
	result.insert(('d', ' '), 'д');
	result.insert(('e', ' '), 'е');
	result.insert(('o', 'j'), 'ё');
	result.insert(('o', 'й'), 'ё');
	result.insert(('h', 'z'), 'ж');
	result.insert(('h', 'з'), 'ж');
	result.insert(('z', ' '), 'з');
	result.insert(('i', ' '), 'и');
	result.insert(('j', ' '), 'й');
	result.insert(('k', ' '), 'к');
	result.insert(('l', ' '), 'л');
	result.insert(('m', ' '), 'м');
	result.insert(('n', ' '), 'н');
	result.insert(('o', ' '), 'о');
	result.insert(('p', ' '), 'п');
	result.insert(('r', ' '), 'р');
	result.insert(('s', ' '), 'с');
	result.insert(('t', ' '), 'т');
	result.insert(('u', ' '), 'у');
	result.insert(('f', ' '), 'ф');
	result.insert(('h', ' '), 'х');
	result.insert(('x', ' '), 'х');
	result.insert(('c', ' '), 'ц');
	result.insert(('h', 'c'), 'ч');
	result.insert(('h', 'ц'), 'ч');
	result.insert(('h', 'h'), 'ш');
	result.insert(('h', 'с'), 'ш');
	result.insert(('h', 'ш'), 'щ');
	result.insert(('w', ' '), 'щ');
	result.insert(('#', ' '), 'ъ');
	result.insert(('y', ' '), 'ы');
	result.insert(('\'', ' '), 'ь');
	result.insert(('e', 'j'), 'э');
	result.insert(('e', 'й'), 'э');
	result.insert(('u', 'j'), 'ю');
	result.insert(('u', 'й'), 'ю');
	result.insert(('a', 'j'), 'я');
	result.insert(('a', 'й'), 'я');

	result.insert(('A', ' '), 'А');
	result.insert(('B', ' '), 'Б');
	result.insert(('V', ' '), 'В');
	result.insert(('G', ' '), 'Г');
	result.insert(('D', ' '), 'Д');
	result.insert(('E', ' '), 'Е');
	result.insert(('O', 'J'), 'Ё');
	result.insert(('O', 'Й'), 'Ё');
	result.insert(('H', 'Z'), 'Ж');
	result.insert(('H', 'З'), 'Ж');
	result.insert(('Z', ' '), 'З');
	result.insert(('I', ' '), 'И');
	result.insert(('J', ' '), 'Й');
	result.insert(('K', ' '), 'К');
	result.insert(('L', ' '), 'Л');
	result.insert(('M', ' '), 'М');
	result.insert(('N', ' '), 'Н');
	result.insert(('O', ' '), 'О');
	result.insert(('P', ' '), 'П');
	result.insert(('R', ' '), 'Р');
	result.insert(('S', ' '), 'С');
	result.insert(('T', ' '), 'Т');
	result.insert(('U', ' '), 'У');
	result.insert(('F', ' '), 'Ф');
	result.insert(('H', ' '), 'Х');
	result.insert(('X', ' '), 'Х');
	result.insert(('C', ' '), 'Ц');
	result.insert(('H', 'C'), 'Ч');
	result.insert(('H', 'Ц'), 'Ч');
	result.insert(('H', 'H'), 'Ш');
	result.insert(('H', 'С'), 'Ш');
	result.insert(('H', 'Ш'), 'Щ');
	result.insert(('W', ' '), 'Щ');
	result.insert(('#', 'ъ'), 'Ъ');
	result.insert(('Y', ' '), 'Ы');
	result.insert(('\'', 'ь'), 'Ь');
	result.insert(('E', 'J'), 'Э');
	result.insert(('E', 'Й'), 'Э');
	result.insert(('U', 'J'), 'Ю');
	result.insert(('U', 'Й'), 'Ю');
	result.insert(('A', 'J'), 'Я');
	result.insert(('A', 'Й'), 'Я');

	result
}
<|endoftext|>


<commit_before>//! Support for serde integration. Enable this with the `serde` feature.
//!
//! To encode/decode type that implement serde's trait, you can use:
//! - [decode_borrowed_from_slice]
//! - [decode_from_slice]
//! - [encode_to_slice]
//! - [encode_to_vec]
//!
//! For interop with bincode's [Decode]/[Encode], you can use:
//! - [Compat]
//! - [BorrowCompat]
//!
//! For interop with bincode's `derive` feature, you can use the `#[bincode(with_serde)]` attribute on each field that implements serde's traits.
//!
//! ```
//! # #[cfg(feature = "derive")]
//! # mod foo {
//! # use bincode::{Decode, Encode};
//! # use serde_derive::{Deserialize, Serialize};
//! #[derive(Serialize, Deserialize)]
//! # #[serde(crate = "serde_incl")]
//! pub struct SerdeType {
//!     // ...
//! }
//!
//! #[derive(Decode, Encode)]
//! pub struct StructWithSerde {
//!     #[bincode(with_serde)]
//!     pub serde: SerdeType,
//! }
//!
//! #[derive(Decode, Encode)]
//! pub enum EnumWithSerde {
//!     Unit(#[bincode(with_serde)] SerdeType),
//!     Struct {
//!         #[bincode(with_serde)]
//!         serde: SerdeType,
//!     },
//! }
//! # }
//! ```
//!
//! # `alloc` and `no_std`
//!
//! The `serde` feature enables both `alloc` and `std` at this point in time.
//! To use bincode and serde on no_std targets, try one of the following features:
//!
//! - `serde_alloc`: enables `serde` and `alloc`
//! - `serde_no_std`: enables `serde` without `alloc` or `std`
//!
//! # Known issues
//!
//! Currently the `serde` feature will automatically enable the `alloc` and `std` feature. If you're running in a `#[no_std]` environment consider using bincode's own derive macros.
//!
//! Because bincode is a format without meta data, there are several known issues with serde's `skip` attributes. Please do not use `skip` attributes if you plan on using bincode, or use bincode's own `derive` macros.
//!
//! This includes:
//! - `#[serde(skip)]`
//! - `#[serde(skip_serializing)]`
//! - `#[serde(skip_deserializing)]`
//! - `#[serde(skip_serializing_if = "path")]`
//! - `#[serde(flatten)]`
//!
//! **Using any of the above attributes can and will cause issues with bincode and will result in lost data**. Consider using bincode's own derive macro instead.
//!
//! [Decode]: ../de/trait.Decode.html
//! [Encode]: ../enc/trait.Encode.html

mod de_borrowed;
mod de_owned;
mod ser;

pub use self::de_borrowed::*;
pub use self::de_owned::*;
pub use self::ser::*;

/// A serde-specific error that occured while decoding.
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum DecodeError {
    /// Bincode does not support serde's `any` decoding feature
    AnyNotSupported,

    /// Bincode does not support serde identifiers
    IdentifierNotSupported,

    /// Bincode does not support serde's `ignored_any`
    IgnoredAnyNotSupported,

    /// Serde tried decoding a borrowed value from an owned reader. Use `serde_decode_borrowed_from_*` instead
    CannotBorrowOwnedData,

    /// Could not allocate data like `String` and `Vec<u8>`
    #[cfg(not(feature = "alloc"))]
    CannotAllocate,

    /// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
    #[cfg(not(feature = "alloc"))]
    CustomError,
}

#[cfg(feature = "alloc")]
impl serde_incl::de::Error for crate::error::DecodeError {
    fn custom<T>(msg: T) -> Self
    where
        T: core::fmt::Display,
    {
        use alloc::string::ToString;
        Self::OtherString(msg.to_string())
    }
}

#[cfg(not(feature = "std"))]
impl serde_incl::de::StdError for crate::error::DecodeError {}

#[cfg(not(feature = "alloc"))]
impl serde_incl::de::Error for crate::error::DecodeError {
    fn custom<T>(_: T) -> Self
    where
        T: core::fmt::Display,
    {
        DecodeError::CustomError.into()
    }
}

#[allow(clippy::from_over_into)]
impl Into<crate::error::DecodeError> for DecodeError {
    fn into(self) -> crate::error::DecodeError {
        crate::error::DecodeError::Serde(self)
    }
}

/// A serde-specific error that occured while encoding.
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum EncodeError {
    /// Serde provided bincode with a sequence without a length, which is not supported in bincode
    SequenceMustHaveLength,

    /// [Serializer::collect_str] got called but bincode was unable to allocate memory.
    #[cfg(not(feature = "alloc"))]
    CannotCollectStr,

    /// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
    #[cfg(not(feature = "alloc"))]
    CustomError,
}

#[allow(clippy::from_over_into)]
impl Into<crate::error::EncodeError> for EncodeError {
    fn into(self) -> crate::error::EncodeError {
        crate::error::EncodeError::Serde(self)
    }
}

#[cfg(feature = "alloc")]
impl serde_incl::ser::Error for crate::error::EncodeError {
    fn custom<T>(msg: T) -> Self
    where
        T: core::fmt::Display,
    {
        use alloc::string::ToString;

        Self::OtherString(msg.to_string())
    }
}

#[cfg(not(feature = "std"))]
impl serde_incl::de::StdError for crate::error::EncodeError {}

#[cfg(not(feature = "alloc"))]
impl serde_incl::ser::Error for crate::error::EncodeError {
    fn custom<T>(_: T) -> Self
    where
        T: core::fmt::Display,
    {
        EncodeError::CustomError.into()
    }
}

/// Wrapper struct that implements [Decode] and [Encode] on any type that implements serde's [DeserializeOwned] and [Serialize] respectively.
///
/// This works for most types, but if you're dealing with borrowed data consider using [BorrowCompat] instead.
///
/// [Decode]: ../de/trait.Decode.html
/// [Encode]: ../enc/trait.Encode.html
/// [DeserializeOwned]: https://docs.rs/serde/1/serde/de/trait.DeserializeOwned.html
/// [Serialize]: https://docs.rs/serde/1/serde/trait.Serialize.html
pub struct Compat<T>(pub T);

impl<T> crate::Decode for Compat<T>
where
    T: serde_incl::de::DeserializeOwned,
{
    fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
        let serde_decoder = de_owned::SerdeDecoder { de: decoder };
        T::deserialize(serde_decoder).map(Compat)
    }
}

impl<T> crate::Encode for Compat<T>
where
    T: serde_incl::Serialize,
{
    fn encode<E: crate::enc::Encoder>(
        &self,
        encoder: &mut E,
    ) -> Result<(), crate::error::EncodeError> {
        let serializer = ser::SerdeEncoder { enc: encoder };
        self.0.serialize(serializer)?;
        Ok(())
    }
}

/// Wrapper struct that implements [BorrowDecode] and [Encode] on any type that implements serde's [Deserialize] and [Serialize] respectively. This is mostly used on `&[u8]` and `&str`, for other types consider using [Compat] instead.
///
/// [BorrowDecode]: ../de/trait.BorrowDecode.html
/// [Encode]: ../enc/trait.Encode.html
/// [Deserialize]: https://docs.rs/serde/1/serde/de/trait.Deserialize.html
/// [Serialize]: https://docs.rs/serde/1/serde/trait.Serialize.html
pub struct BorrowCompat<T>(pub T);

impl<'de, T> crate::de::BorrowDecode<'de> for BorrowCompat<T>
where
    T: serde_incl::de::Deserialize<'de>,
{
    fn borrow_decode<D: crate::de::BorrowDecoder<'de>>(
        decoder: &mut D,
    ) -> Result<Self, crate::error::DecodeError> {
        let serde_decoder = de_borrowed::SerdeDecoder {
            de: decoder,
            pd: core::marker::PhantomData,
        };
        T::deserialize(serde_decoder).map(BorrowCompat)
    }
}

impl<T> crate::Encode for BorrowCompat<T>
where
    T: serde_incl::Serialize,
{
    fn encode<E: crate::enc::Encoder>(
        &self,
        encoder: &mut E,
    ) -> Result<(), crate::error::EncodeError> {
        let serializer = ser::SerdeEncoder { enc: encoder };
        self.0.serialize(serializer)?;
        Ok(())
    }
}
<commit_msg>Added #[serde(untagged)] to the documentation of attributes that don't work (#486)<commit_after>//! Support for serde integration. Enable this with the `serde` feature.
//!
//! To encode/decode type that implement serde's trait, you can use:
//! - [decode_borrowed_from_slice]
//! - [decode_from_slice]
//! - [encode_to_slice]
//! - [encode_to_vec]
//!
//! For interop with bincode's [Decode]/[Encode], you can use:
//! - [Compat]
//! - [BorrowCompat]
//!
//! For interop with bincode's `derive` feature, you can use the `#[bincode(with_serde)]` attribute on each field that implements serde's traits.
//!
//! ```
//! # #[cfg(feature = "derive")]
//! # mod foo {
//! # use bincode::{Decode, Encode};
//! # use serde_derive::{Deserialize, Serialize};
//! #[derive(Serialize, Deserialize)]
//! # #[serde(crate = "serde_incl")]
//! pub struct SerdeType {
//!     // ...
//! }
//!
//! #[derive(Decode, Encode)]
//! pub struct StructWithSerde {
//!     #[bincode(with_serde)]
//!     pub serde: SerdeType,
//! }
//!
//! #[derive(Decode, Encode)]
//! pub enum EnumWithSerde {
//!     Unit(#[bincode(with_serde)] SerdeType),
//!     Struct {
//!         #[bincode(with_serde)]
//!         serde: SerdeType,
//!     },
//! }
//! # }
//! ```
//!
//! # `alloc` and `no_std`
//!
//! The `serde` feature enables both `alloc` and `std` at this point in time.
//! To use bincode and serde on no_std targets, try one of the following features:
//!
//! - `serde_alloc`: enables `serde` and `alloc`
//! - `serde_no_std`: enables `serde` without `alloc` or `std`
//!
//! # Known issues
//!
//! Currently the `serde` feature will automatically enable the `alloc` and `std` feature. If you're running in a `#[no_std]` environment consider using bincode's own derive macros.
//!
//! Because bincode is a format without meta data, there are several known issues with serde's attributes. Please do not use any of the following attributes if you plan on using bincode, or use bincode's own `derive` macros.
//! - `#[serde(skip)]`
//! - `#[serde(skip_serializing)]`
//! - `#[serde(skip_deserializing)]`
//! - `#[serde(skip_serializing_if = "path")]`
//! - `#[serde(flatten)]`
//! - `#[serde(untagged)]`
//!
//! **Using any of the above attributes can and will cause issues with bincode and will result in lost data**. Consider using bincode's own derive macro instead.
//!
//! [Decode]: ../de/trait.Decode.html
//! [Encode]: ../enc/trait.Encode.html

mod de_borrowed;
mod de_owned;
mod ser;

pub use self::de_borrowed::*;
pub use self::de_owned::*;
pub use self::ser::*;

/// A serde-specific error that occured while decoding.
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum DecodeError {
    /// Bincode does not support serde's `any` decoding feature
    AnyNotSupported,

    /// Bincode does not support serde identifiers
    IdentifierNotSupported,

    /// Bincode does not support serde's `ignored_any`
    IgnoredAnyNotSupported,

    /// Serde tried decoding a borrowed value from an owned reader. Use `serde_decode_borrowed_from_*` instead
    CannotBorrowOwnedData,

    /// Could not allocate data like `String` and `Vec<u8>`
    #[cfg(not(feature = "alloc"))]
    CannotAllocate,

    /// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
    #[cfg(not(feature = "alloc"))]
    CustomError,
}

#[cfg(feature = "alloc")]
impl serde_incl::de::Error for crate::error::DecodeError {
    fn custom<T>(msg: T) -> Self
    where
        T: core::fmt::Display,
    {
        use alloc::string::ToString;
        Self::OtherString(msg.to_string())
    }
}

#[cfg(not(feature = "std"))]
impl serde_incl::de::StdError for crate::error::DecodeError {}

#[cfg(not(feature = "alloc"))]
impl serde_incl::de::Error for crate::error::DecodeError {
    fn custom<T>(_: T) -> Self
    where
        T: core::fmt::Display,
    {
        DecodeError::CustomError.into()
    }
}

#[allow(clippy::from_over_into)]
impl Into<crate::error::DecodeError> for DecodeError {
    fn into(self) -> crate::error::DecodeError {
        crate::error::DecodeError::Serde(self)
    }
}

/// A serde-specific error that occured while encoding.
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub enum EncodeError {
    /// Serde provided bincode with a sequence without a length, which is not supported in bincode
    SequenceMustHaveLength,

    /// [Serializer::collect_str] got called but bincode was unable to allocate memory.
    #[cfg(not(feature = "alloc"))]
    CannotCollectStr,

    /// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
    #[cfg(not(feature = "alloc"))]
    CustomError,
}

#[allow(clippy::from_over_into)]
impl Into<crate::error::EncodeError> for EncodeError {
    fn into(self) -> crate::error::EncodeError {
        crate::error::EncodeError::Serde(self)
    }
}

#[cfg(feature = "alloc")]
impl serde_incl::ser::Error for crate::error::EncodeError {
    fn custom<T>(msg: T) -> Self
    where
        T: core::fmt::Display,
    {
        use alloc::string::ToString;

        Self::OtherString(msg.to_string())
    }
}

#[cfg(not(feature = "std"))]
impl serde_incl::de::StdError for crate::error::EncodeError {}

#[cfg(not(feature = "alloc"))]
impl serde_incl::ser::Error for crate::error::EncodeError {
    fn custom<T>(_: T) -> Self
    where
        T: core::fmt::Display,
    {
        EncodeError::CustomError.into()
    }
}

/// Wrapper struct that implements [Decode] and [Encode] on any type that implements serde's [DeserializeOwned] and [Serialize] respectively.
///
/// This works for most types, but if you're dealing with borrowed data consider using [BorrowCompat] instead.
///
/// [Decode]: ../de/trait.Decode.html
/// [Encode]: ../enc/trait.Encode.html
/// [DeserializeOwned]: https://docs.rs/serde/1/serde/de/trait.DeserializeOwned.html
/// [Serialize]: https://docs.rs/serde/1/serde/trait.Serialize.html
pub struct Compat<T>(pub T);

impl<T> crate::Decode for Compat<T>
where
    T: serde_incl::de::DeserializeOwned,
{
    fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
        let serde_decoder = de_owned::SerdeDecoder { de: decoder };
        T::deserialize(serde_decoder).map(Compat)
    }
}

impl<T> crate::Encode for Compat<T>
where
    T: serde_incl::Serialize,
{
    fn encode<E: crate::enc::Encoder>(
        &self,
        encoder: &mut E,
    ) -> Result<(), crate::error::EncodeError> {
        let serializer = ser::SerdeEncoder { enc: encoder };
        self.0.serialize(serializer)?;
        Ok(())
    }
}

/// Wrapper struct that implements [BorrowDecode] and [Encode] on any type that implements serde's [Deserialize] and [Serialize] respectively. This is mostly used on `&[u8]` and `&str`, for other types consider using [Compat] instead.
///
/// [BorrowDecode]: ../de/trait.BorrowDecode.html
/// [Encode]: ../enc/trait.Encode.html
/// [Deserialize]: https://docs.rs/serde/1/serde/de/trait.Deserialize.html
/// [Serialize]: https://docs.rs/serde/1/serde/trait.Serialize.html
pub struct BorrowCompat<T>(pub T);

impl<'de, T> crate::de::BorrowDecode<'de> for BorrowCompat<T>
where
    T: serde_incl::de::Deserialize<'de>,
{
    fn borrow_decode<D: crate::de::BorrowDecoder<'de>>(
        decoder: &mut D,
    ) -> Result<Self, crate::error::DecodeError> {
        let serde_decoder = de_borrowed::SerdeDecoder {
            de: decoder,
            pd: core::marker::PhantomData,
        };
        T::deserialize(serde_decoder).map(BorrowCompat)
    }
}

impl<T> crate::Encode for BorrowCompat<T>
where
    T: serde_incl::Serialize,
{
    fn encode<E: crate::enc::Encoder>(
        &self,
        encoder: &mut E,
    ) -> Result<(), crate::error::EncodeError> {
        let serializer = ser::SerdeEncoder { enc: encoder };
        self.0.serialize(serializer)?;
        Ok(())
    }
}
<|endoftext|>


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

#![feature(test)]

extern crate test;
extern crate xi_core_lib as xi_core;
extern crate xi_rope;

use crate::xi_core::tabs::BufferId;
use crate::xi_core::view::View;
use test::Bencher;
use xi_rope::Rope;

fn build_short_lines(n: usize) -> String {
    let line =
        "See it, the beautiful ball Poised in the toyshop window, Rounder than sun or moon.\n";
    let mut s = String::new();
    for _ in 0..n {
        s += line;
    }
    s
}

#[bench]
fn line_of_offset_no_breaks(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(1_000));
    let view = View::new(1.into(), BufferId::new(2));

    let total_bytes = text.len();
    b.iter(|| {
        for i in 0..total_bytes {
            let _line = view.line_of_offset(&text, i);
        }
    })
}

#[bench]
fn line_of_offset_col_breaks(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(1_000));
    let mut view = View::new(1.into(), BufferId::new(2));
    view.debug_force_rewrap_cols(&text, 20);

    let total_bytes = text.len();
    b.iter(|| {
        for i in 0..total_bytes {
            let _line = view.line_of_offset(&text, i);
        }
    })
}

#[bench]
fn offset_of_line_no_breaks(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(1_000));
    let view = View::new(1.into(), BufferId::new(2));

    b.iter(|| {
        for i in 0..1_000 {
            let _line = view.offset_of_line(&text, i);
        }
    })
}

#[bench]
fn offset_of_line_col_breaks(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(1_000));
    let mut view = View::new(1.into(), BufferId::new(2));
    view.debug_force_rewrap_cols(&text, 20);

    b.iter(|| {
        for i in 0..1000 {
            let _line = view.offset_of_line(&text, i);
        }
    })
}
<commit_msg>Make wrap benches more stressful<commit_after>// Copyright 2018 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(test)]

extern crate test;
extern crate xi_core_lib as xi_core;
extern crate xi_rope;

use crate::xi_core::tabs::BufferId;
use crate::xi_core::view::View;
use test::Bencher;
use xi_rope::Rope;

fn build_short_lines(n: usize) -> String {
    let line =
        "See it, the beautiful ball Poised in the toyshop window, Rounder than sun or moon.\n";
    let mut s = String::new();
    for _ in 0..n {
        s += line;
    }
    s
}

#[bench]
fn line_of_offset_no_breaks(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(10_000));
    let view = View::new(1.into(), BufferId::new(2));

    let total_bytes = text.len();
    b.iter(|| {
        for i in 0..total_bytes {
            let _line = view.line_of_offset(&text, i);
        }
    })
}

#[bench]
fn line_of_offset_col_breaks(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(10_000));
    let mut view = View::new(1.into(), BufferId::new(2));
    view.debug_force_rewrap_cols(&text, 20);

    let total_bytes = text.len();
    b.iter(|| {
        for i in 0..total_bytes {
            let _line = view.line_of_offset(&text, i);
        }
    })
}

#[bench]
fn offset_of_line_no_breaks(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(10_000));
    let view = View::new(1.into(), BufferId::new(2));

    b.iter(|| {
        for i in 0..10_000 {
            let _line = view.offset_of_line(&text, i);
        }
    })
}

#[bench]
fn offset_of_line_col_breaks(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(10_000));
    let mut view = View::new(1.into(), BufferId::new(2));
    view.debug_force_rewrap_cols(&text, 20);

    b.iter(|| {
        for i in 0..10_000 {
            let _line = view.offset_of_line(&text, i);
        }
    })
}
<|endoftext|>


<commit_before>use byteorder::{BigEndian, ByteOrder};

pub fn to_byte_array(value: u32) -> [u8; 4] {
    let mut raw = [0u8; 4];
    BigEndian::write_u32(&mut raw, value);
    raw
}
<commit_msg>Binary array to string<commit_after>use std::fmt::Write;
use byteorder::{BigEndian, ByteOrder};

pub fn to_byte_array(value: u32) -> [u8; 4] {
    let mut raw = [0u8; 4];
    BigEndian::write_u32(&mut raw, value);
    raw
}

pub fn to_string(data: &[u8]) -> String {
    let mut s = String::new();
    for (i, &byte) in data.iter().enumerate() {
        if i % 16 == 0 {
            write!(&mut s, "\n").unwrap();
        } else if i % 8 == 0 {
            write!(&mut s, " ").unwrap();
        }
        write!(&mut s, "{:02X} ", byte).unwrap();
    }
    s
}
<|endoftext|>


<commit_before>use std::rc::{Rc, Weak};
use std::cell::RefCell;
use std::borrow::Borrow;
use dovahkiin::types::custom_types::id::Id;
use smallvec::SmallVec;
use std::sync::Arc;
use ram::chunk::Chunks;
use ram::cell::Cell;
use dovahkiin::types;
use dovahkiin::types::custom_types::map::key_hash;
use dovahkiin::types::value::{ValueIter};
use dovahkiin::types::{Value, PrimitiveArray};
use utils::lru_cache::LRUCache;
use parking_lot::{Mutex, MutexGuard};
use std::io::Cursor;
use std::ops::Index;
use std::cmp::Ordering;

lazy_static! {
    pub static ref ENTRIES_KEY_HASH : u64 = key_hash("entries");
    pub static ref KEYS_KEY_HASH : u64 = key_hash("keys");
    pub static ref PREV_PAGE_KEY_HASH : u64 = key_hash("prev");
    pub static ref NEXT_PAGE_KEY_HASH : u64 = key_hash("next");
}

type EntryKey = SmallVec<[u8; 32]>;
type CachedExtNodeRef = Arc<CachedExtNode>;

pub struct LSMTree {
    num_levels: u8,
    levels: Vec<Rc<BPlusTree>>,
}

 trait BPlusTree {
      fn root(&self) -> &Node;
      fn root_mut(&self) -> &mut Node;
      fn get_height(&self) -> u32;
      fn set_height(&mut self) -> u32;
      fn get_num_nodes(&self) -> u32;
      fn set_num_nodes(&self) -> u32;
      fn page_size(&self) -> usize;
      fn chunks(&self) -> &Arc<Chunks>;
      fn page_cache(&self) -> MutexGuard<LRUCache<Id, CachedExtNodeRef>>;
      fn get_page_direct(&self, id: &Id) -> CachedExtNodeRef {
          let cell = self.chunks().read_cell(id).unwrap(); // should crash if not exists
          let keys = &cell.data[*KEYS_KEY_HASH];
          let keys_len = keys.len().unwrap();
          let mut v_node = CachedExtNode {
              keys: Vec::new(),
              delimiters: Vec::new(),
          };
          for key in keys.iter_value().unwrap() {
              let key = if let Value::PrimArray(PrimitiveArray::U8(ref array)) = key {
                  array
              } else { panic!("invalid entry") };
              let mut id_cursor = Cursor::new(&key[key.len() - 16 ..]);
              let id = Id::from_binary(&mut id_cursor).unwrap(); // read id from tailing 128 bits
              v_node.keys.push(EntryKey::from_slice(key.as_slice()));
              v_node.delimiters.push(Delimiter::External(id));
          }
          return Arc::new(v_node);
      }
      fn get_page(&self, id: &Id) -> CachedExtNodeRef {
          self.page_cache().get_or_fetch(id).unwrap().clone()
      }
      fn get(&self, key: &EntryKey) -> Option<Id> {
          self.search(self.root(), key, self.get_height())
      }
      fn search<'a>(&self, node: &'a Node, key: &EntryKey, ht: u32) -> Option<Id> {
          let keys = node.keys();
          let index = keys
              .search(key)
              .map(|i| i + 1)
              .unwrap_or_else(|i| i);
          if ht == 0 { // persist page
              match &node.delimiters().get(index) {
                  Some(Delimiter::External(id)) => Some(*id),
                  Some(Delimiter::Internal(_)) => panic!("Error on leaf delimiter type"),
                  None => panic!("Error on leaf delimiter is none")
              }
          } else {
              match &node.delimiters().get(index) {
                  Some(Delimiter::External(ref id)) => {
                      assert_eq!(ht, 0);
                      // search in leaf page
                      let page = self.get_page(id);
                      return self.search(&*page, key, ht - 1);
                  },
                  Some(Delimiter::Internal(node)) => return self.search(node.borrow(), key, ht - 1),
                  None => return None
              }
          }
      }
 }

enum Delimiter {
    External(Id), // to leaf
    Internal(Box<Node>) // to higher level node
}

trait Array<T> where T: Ord {
    #[inline]
    fn index_of(&self, index: usize) -> &T;
    #[inline]
    fn size(&self) -> usize;
    #[inline]
    fn search(&self, item: &T) -> Result<usize, usize>;
    #[inline]
    fn get(&self, index: usize) -> Option<&T>;
}

trait Keys : Array<EntryKey> {}
trait Delimiters : Array<Delimiter> {}
impl Keys for [EntryKey] {}
impl Delimiters for [Delimiter] {}
impl <T> Array<T> for [T] where T: Ord {
    #[inline]
    fn index_of(&self, index: usize) -> &T { &self[index] }

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

    #[inline]
    fn search(&self, item: &T) -> Result<usize, usize> { self.binary_search(item) }

    #[inline]
    fn get(&self, index: usize) -> Option<&T> {
        if index >= self.size() { None } else { Some(&self[index]) }
    }
}

trait Node {
    fn keys(&self) -> &Keys;
    fn delimiters(&self) -> &Delimiters;
    fn keys_mut(&mut self) -> &mut Keys;
    fn delimiters_mut(&mut self) -> &mut Delimiters;
}

struct CachedExtNode {
    keys: Vec<EntryKey>,
    delimiters: Vec<Delimiter>
}

impl Node for CachedExtNode {
    fn keys(&self) -> &Keys {
        return self.keys.as_slice()
    }

    fn delimiters(&self) -> &Delimiters {
        return self.delimiters.as_slice();
    }

    fn keys_mut(&mut self) -> &mut Keys {
        panic!()
    }

    fn delimiters_mut(&mut self) -> &mut Delimiters {
        panic!()
    }
}

impl <T> Index<usize> for Array<T> where T: Ord {
    type Output = T;

    fn index(&self, index: usize) -> &<Self as Index<usize>>::Output {
        self.index_of(index)
    }
}

macro_rules! impl_nodes {
    ($(($level: ident, $entry_size: expr, $delimiter_size: expr)),+) => {
        $(
            mod $level {
                use super::*;

                type LEntryKeys = [EntryKey; $entry_size];

                impl Array<EntryKey> for LEntryKeys {
                    #[inline]
                    fn size(&self) -> usize { $entry_size }
                    #[inline]
                    fn index_of(&self, index: usize) -> &EntryKey { &self[index] }
                    #[inline]
                    fn search(&self, item: &T) -> Result<usize, usize> {
                        self.binary_search(item)
                    }
                    #[inline]
                    fn get(&self, index: usize) -> Option<&EntryKey> {
                        if index >= $entry_size { None } else { Some(&self[index]) }
                    }
                }

                type LDelimiter = [Delimiter; $delimiter_size];

                impl Array<Delimiter> for LDelimiter {
                    #[inline]
                    fn size(&self) -> usize { $delimiter_size }
                    #[inline]
                    fn index_of(&self, index: usize) -> &Delimiter { &self[index] }
                    #[inline]
                    fn search(&self, item: &Delimiter) -> Result<usize, usize> {
                        self.binary_search(item)
                    }
                    #[inline]
                    fn get(&self, index: usize) -> Option<&Delimiter> {
                        if index >= $entry_size { None } else { Some(&self[index]) }
                    }
                }

                impl Delimiters for LDelimiter {}
                impl Keys for LEntryKeys {}

                struct LNode {
                    id: Id,
                    keys: LEntryKeys,
                    delimeters: LDelimiter,
                }

                impl Node for LNode {
                    #[inline]
                    fn keys(&self) -> &Keys {
                        &self.keys
                    }
                    #[inline]
                    fn delimiters(&self) -> &Delimiters {
                        &self.delimeters
                    }
                    #[inline]
                    fn keys_mut(&mut self) -> &mut Keys {
                        &mut self.keys
                    }
                    #[inline]
                    fn delimiters_mut(&mut self) -> &mut Delimiters {
                        &mut self.delimeters
                    }
                }
            }
        )+
    };
}

impl_nodes!((level_0, 2, 3), (level_1, 20, 21), (level_2, 200, 201), (level_3, 2000, 2001), (level_4, 20000, 20001));

impl Ord for Delimiter {
    fn cmp(&self, other: &Self) -> Ordering {
        panic!()
    }
}
impl PartialOrd for Delimiter {
    fn partial_cmp(&self, other: &Rhs) -> Option<Ordering> {
        panic!()
    }
}
impl Eq for Delimiter {}
impl PartialEq for Delimiter {
    fn eq(&self, other: &Rhs) -> bool {
        panic!()
    }
}<commit_msg>modeling node mutation<commit_after>use std::rc::{Rc, Weak};
use std::cell::RefCell;
use std::borrow::Borrow;
use dovahkiin::types::custom_types::id::Id;
use smallvec::SmallVec;
use std::sync::Arc;
use ram::chunk::Chunks;
use ram::cell::Cell;
use dovahkiin::types;
use dovahkiin::types::custom_types::map::key_hash;
use dovahkiin::types::value::{ValueIter};
use dovahkiin::types::{Value, PrimitiveArray};
use utils::lru_cache::LRUCache;
use parking_lot::{Mutex, MutexGuard};
use std::io::Cursor;
use std::ops::Index;
use std::cmp::Ordering;

lazy_static! {
    pub static ref ENTRIES_KEY_HASH : u64 = key_hash("entries");
    pub static ref KEYS_KEY_HASH : u64 = key_hash("keys");
    pub static ref PREV_PAGE_KEY_HASH : u64 = key_hash("prev");
    pub static ref NEXT_PAGE_KEY_HASH : u64 = key_hash("next");
}

type EntryKey = SmallVec<[u8; 32]>;
type CachedExtNodeRef = Arc<CachedExtNode>;

pub struct LSMTree {
    num_levels: u8,
    levels: Vec<Rc<BPlusTree>>,
}

 trait BPlusTree {
      fn root(&self) -> &Node;
      fn root_mut(&self) -> &mut Node;
      fn get_height(&self) -> u32;
      fn set_height(&mut self) -> u32;
      fn get_num_nodes(&self) -> u32;
      fn set_num_nodes(&self) -> u32;
      fn page_size(&self) -> u32;
      fn chunks(&self) -> &Arc<Chunks>;
      fn page_cache(&self) -> MutexGuard<LRUCache<Id, CachedExtNodeRef>>;
      fn get_page_direct(&self, id: &Id) -> CachedExtNodeRef {
          let cell = self.chunks().read_cell(id).unwrap(); // should crash if not exists
          let keys = &cell.data[*KEYS_KEY_HASH];
          let keys_len = keys.len().unwrap();
          let mut v_node = CachedExtNode {
              keys: Vec::new(),
              ids: Vec::new(),
              cap: self.page_size()
          };
          for key in keys.iter_value().unwrap() {
              let key = if let Value::PrimArray(PrimitiveArray::U8(ref array)) = key {
                  EntryKey::from_slice(array.as_slice())
              } else { panic!("invalid entry") };
              let id = id_from_key(&key);
              v_node.keys.push(EntryKey::from_slice(key.as_slice()));
              v_node.ids.push(Delimiter::External(id));
          }
          return Arc::new(v_node);
      }
      fn get_page(&self, id: &Id) -> CachedExtNodeRef {
          self.page_cache().get_or_fetch(id).unwrap().clone()
      }
      fn get(&self, key: &EntryKey) -> Option<Id> {
          self.search(self.root(), key, self.get_height())
      }
      fn search<'a>(&self, node: &'a Node, key: &EntryKey, ht: u32) -> Option<Id> {
          if ht == 0 { // persist page
              let search_result = node.keys()
                  .search(key);
              let index = if let Ok(i) = search_result { i } else { return None };
              match &node.delimiters().get(index) {
                  Some(Delimiter::External(id)) => Some(*id),
                  Some(Delimiter::Internal(_)) => panic!("Error on leaf delimiter type"),
                  None => panic!("Error on leaf delimiter is none")
              }
          } else {
              let index = node.keys()
                  .search(key)
                  .map(|i| i + 1)
                  .unwrap_or_else(|i| i);
              match &node.delimiters().get(index) {
                  Some(Delimiter::External(ref id)) => {
                      assert_eq!(ht, 0);
                      // search in leaf page
                      let page = self.get_page(id);
                      return self.search(&*page, key, ht - 1);
                  },
                  Some(Delimiter::Internal(node)) => return self.search(node.borrow(), key, ht - 1),
                  None => return None
              }
          }
      }
     fn insert(&self, key: &EntryKey, value: &Id) {
         unimplemented!()
     }
     fn put<'a>(&self, node: &'a Node, key: &EntryKey, ht: u32) {
         let keys = node.keys();
         let index = keys
             .search(key)
             .map(|i| i + 1)
             .unwrap_or_else(|i| i);
         if ht == 0 {

         }
     }
 }

enum Delimiter {
    External(Id), // to leaf
    Internal(Box<Node>) // to higher level node
}

trait Array<T> where T: Ord {
    #[inline]
    fn index_of(&self, index: usize) -> &T;
    #[inline]
    fn size(&self) -> usize;
    #[inline]
    fn search(&self, item: &T) -> Result<usize, usize>;
    #[inline]
    fn get(&self, index: usize) -> Option<&T>;
}

trait Keys : Array<EntryKey> {}
trait Delimiters : Array<Delimiter> {}
impl Keys for [EntryKey] {}
impl Delimiters for [Delimiter] {}
impl <T> Array<T> for [T] where T: Ord {
    #[inline]
    fn index_of(&self, index: usize) -> &T { &self[index] }

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

    #[inline]
    fn search(&self, item: &T) -> Result<usize, usize> { self.binary_search(item) }

    #[inline]
    fn get(&self, index: usize) -> Option<&T> {
        if index >= self.size() { None } else { Some(&self[index]) }
    }
}
impl <T> Array<T> for Vec<T> where T: Ord {
    #[inline]
    fn index_of(&self, index: usize) -> &T {
        self.get(index).unwrap()
    }

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

    #[inline]
    fn search(&self, item: &T) -> Result<usize, usize> {
        self.as_slice().binary_search(item)
    }

    #[inline]
    fn get(&self, index: usize) -> Option<&T> {
        if index >= self.len() { None } else { Some(&self[index]) }
    }
}
impl Delimiters for Vec<Delimiter> {}
impl Keys for Vec<EntryKey> {}

trait Node {
    #[inline]
    fn keys(&self) -> &Keys;
    #[inline]
    fn delimiters(&self) -> &Delimiters;
    #[inline]
    fn add(&mut self, key: EntryKey) -> Option<None>;
    #[inline]
    fn del(&mut self, key: &EntryKey);
    #[inline]
    fn merge(&mut self, x: None);
}

struct CachedExtNode {
    keys: Vec<EntryKey>,
    ids: Vec<Delimiter>,
    cap: u32,
}

impl Node for CachedExtNode {
    #[inline]
    fn keys(&self) -> &Keys {
        &self.keys
    }

    #[inline]
    fn delimiters(&self) -> &Delimiters {
        &self.ids
    }

    fn add(&mut self, key: EntryKey) -> Option<Self> {
        let insert_pos = match self.keys.binary_search(&key) {
            Ok(_) => return None, // existed
            Err(i) => i
        };
        let id = id_from_key(&key);
        self.keys.insert(i, key);
        self.ids.insert(i, Delimiter::External(id));
        if self.keys.len() > self.cap as usize {
            // need to split
            let mid = self.keys.len() / 2;
            let keys_2: Vec<_> = self.keys.drain(mid..).collect();
            let ids_2: Vec<_> = self.ids.drain(mid..).collect();
            return Some(CachedExtNode {
                keys: keys_2,
                ids: ids_2,
                cap: self.cap
            });
        } else {
            return None;
        }
    }

    fn del(&mut self, key: &EntryKey) {
        let pos = match self.keys.binary_search(&key) {
            Ok(i) => i, // existed
            Err(i) => return
        };
        self.keys.remove(pos);
        self.ids.remove(pos);
    }

    fn merge(&mut self, mut x: Self) {
        self.keys.append(&mut x.keys);
        self.ids.append(&mut x.ids);
    }
}

trait InterNode {

}

impl <T> Index<usize> for Array<T> where T: Ord {
    type Output = T;

    fn index(&self, index: usize) -> &<Self as Index<usize>>::Output {
        self.index_of(index)
    }
}

macro_rules! impl_nodes {
    ($(($level: ident, $entry_size: expr, $delimiter_size: expr)),+) => {
        $(
            mod $level {
                use super::*;

                type LEntryKeys = [EntryKey; $entry_size];

                impl Array<EntryKey> for LEntryKeys {
                    #[inline]
                    fn size(&self) -> usize { $entry_size }
                    #[inline]
                    fn index_of(&self, index: usize) -> &EntryKey { &self[index] }
                    #[inline]
                    fn search(&self, item: &EntryKey) -> Result<usize, usize> {
                        self.binary_search(item)
                    }
                    #[inline]
                    fn get(&self, index: usize) -> Option<&EntryKey> {
                        if index >= $entry_size { None } else { Some(&self[index]) }
                    }
                }

                type LDelimiter = [Delimiter; $delimiter_size];

                impl Array<Delimiter> for LDelimiter {
                    #[inline]
                    fn size(&self) -> usize { $delimiter_size }
                    #[inline]
                    fn index_of(&self, index: usize) -> &Delimiter { &self[index] }
                    #[inline]
                    fn search(&self, item: &Delimiter) -> Result<usize, usize> {
                        self.binary_search(item)
                    }
                    #[inline]
                    fn get(&self, index: usize) -> Option<&Delimiter> {
                        if index >= $entry_size { None } else { Some(&self[index]) }
                    }
                }

                impl Delimiters for LDelimiter {}
                impl Keys for LEntryKeys {}

                struct LNode {
                    keys: LEntryKeys,
                    delimeters: LDelimiter,
                    pos: u32
                }

                impl Node for LNode {
                    #[inline]
                    fn keys(&self) -> &Keys {
                        &self.keys
                    }
                    #[inline]
                    fn delimiters(&self) -> &Delimiters {
                        &self.delimeters
                    }
                    #[inline]
                    fn add(&mut self, key: EntryKey) -> Option<Node> {
                        unimplemented!()
                    }
                    #[inline]
                    fn del(&mut self, key: &EntryKey) {
                        unimplemented!()
                    }
                    #[inline]
                    fn merge(&mut self, x: Self) {
                        unimplemented!()
                    }
                }
            }
        )+
    };
}

impl_nodes!((level_0, 2, 3), (level_1, 20, 21), (level_2, 200, 201), (level_3, 2000, 2001), (level_4, 20000, 20001));

impl Ord for Delimiter {
    fn cmp(&self, other: &Self) -> Ordering {
        panic!()
    }
}
impl PartialOrd for Delimiter {
    fn partial_cmp(&self, other: &Delimiter) -> Option<Ordering> {
        panic!()
    }
}
impl Eq for Delimiter {}
impl PartialEq for Delimiter {
    fn eq(&self, other: &Delimiter) -> bool {
        panic!()
    }
}

fn id_from_key(key: &EntryKey) -> Id {
    let mut id_cursor = Cursor::new(&key[key.len() - 16 ..]);
    return Id::from_binary(&mut id_cursor).unwrap(); // read id from tailing 128 bits
}<|endoftext|>


<commit_before>#![feature(proc_macro_quote, proc_macro_non_items)]
extern crate proc_macro;

use proc_macro::{TokenStream, quote};

#[proc_macro_derive(ClippyMiniMacroTest)]
pub fn mini_macro(_: TokenStream) -> TokenStream {
    quote!(
        #[allow(unused)] fn needless_take_by_value(s: String) { println!("{}", s.len()); }
    )
}<commit_msg>mini-macro: fix tests with latest rustc (rename feature: proc_macro_non_items -> proc_macro_hygiene).<commit_after>#![feature(proc_macro_quote, proc_macro_hygiene)]
extern crate proc_macro;

use proc_macro::{TokenStream, quote};

#[proc_macro_derive(ClippyMiniMacroTest)]
pub fn mini_macro(_: TokenStream) -> TokenStream {
    quote!(
        #[allow(unused)] fn needless_take_by_value(s: String) { println!("{}", s.len()); }
    )
}
<|endoftext|>


<commit_before>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::filesystem::{DirEntry, DirectoryIterator, FileSystem, ZeroCopyReader, ZeroCopyWriter};
use crate::server::{Reader, Server, Writer};

// Use a file system that does nothing since we are fuzzing the server implementation.
struct NullFs;
impl FileSystem for NullFs {
    type Inode = u64;
    type Handle = u64;
    type DirIter = NullIter;
}

struct NullIter;
impl DirectoryIterator for NullIter {
    fn next(&mut self) -> Option<DirEntry> {
        None
    }
}

/// Fuzz the server implementation.
pub fn fuzz_server<R: Reader + ZeroCopyReader, W: Writer + ZeroCopyWriter>(r: R, w: W) {
    let server = Server::new(NullFs);

    let _ = server.handle_message(r, w);
}
<commit_msg>fuse: Fix build error with fuzzing cfg flag<commit_after>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::filesystem::{DirEntry, DirectoryIterator, FileSystem, ZeroCopyReader, ZeroCopyWriter};
use crate::server::{Mapper, Reader, Server, Writer};

// Use a file system that does nothing since we are fuzzing the server implementation.
struct NullFs;
impl FileSystem for NullFs {
    type Inode = u64;
    type Handle = u64;
    type DirIter = NullIter;
}

struct NullIter;
impl DirectoryIterator for NullIter {
    fn next(&mut self) -> Option<DirEntry> {
        None
    }
}

/// Fuzz the server implementation.
pub fn fuzz_server<R: Reader + ZeroCopyReader, W: Writer + ZeroCopyWriter, M: Mapper>(
    r: R,
    w: W,
    m: M,
) {
    let server = Server::new(NullFs);

    let _ = server.handle_message(r, w, m);
}
<|endoftext|>