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

use xshell::{cmd, read_file};
use xtask::{
    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(&project_root().join("crates")) {
        let text = read_file(&path).unwrap();
        check_todo(&path, &text);
        check_trailing_ws(&path, &text);
        deny_clippy(&path, &text);
        tidy_docs.visit(&path, &text);
    }
    tidy_docs.finish();
}

#[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
        "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 WITH LLVM-exception OR 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/cli.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
        "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_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"];

            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>Add check for dbg! macro<commit_after>use std::{
    collections::HashMap,
    path::{Path, PathBuf},
};

use xshell::{cmd, read_file};
use xtask::{
    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(&project_root().join("crates")) {
        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 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
        "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 WITH LLVM-exception OR 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
        "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
        "completion/src/completions/postfix.rs",
        // The documentation in string literals may contain anything for its own purposes
        "completion/src/lib.rs",
        "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"];

            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>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/reader.rs                                           *
 *                                                        *
 * hprose reader for Rust.                                *
 *                                                        *
 * LastModified: Sep 24, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

extern crate test;

use super::tags::*;
use super::*;

use super::bool_decoder::bool_decode;
use super::i64_decoder::i64_decode;
use super::u64_decoder::u64_decode;
use super::f32_decoder::f32_decode;
use super::f64_decoder::f64_decode;
use super::string_decoder::string_decode;
use super::map_decoder::map_decode;

use std::fmt;
use std::f64;
use std::str;

/// A set of errors that can occur decoding byte slice
#[derive(Clone, PartialEq, Debug)]
pub enum DecoderError {
    ParserError(ParserError),
    CastError(&'static str, &'static str),
    UnexpectedTag(u8, Option<Bytes>)
}

impl fmt::Display for DecoderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DecoderError::CastError(src_type, dst_type) => write!(f, "can't convert {} to {}", src_type, dst_type),
            DecoderError::UnexpectedTag(tag, ref expect_tags_option) => {
                match *expect_tags_option {
                    // todo: format tag as 'c'(0xdd)
                    Some(ref expect_tags) => write!(f, "Tag '{:?}' expected, but '{}' found in stream", expect_tags, tag),
                    None => write!(f, "Unexpected serialize tag '{}' in stream", tag)
                }
            },
            _ => fmt::Debug::fmt(self, f)
        }
    }
}

pub type DecodeResult<T> = Result<T, DecoderError>;

/// Reader is a fine-grained operation struct for Hprose unserialization
pub struct Reader<'a> {
    pub byte_reader: ByteReader<'a>
}

impl<'a> Reader<'a> {
    #[inline]
    pub fn new(buf: &'a [u8], simple: bool) -> Reader<'a> {
        Reader {
            byte_reader: ByteReader::new(buf)
        }
    }

    #[inline]
    pub fn unserialize<T: Decodable>(&mut self) -> DecodeResult<T> {
        self.read()
    }

    #[inline]
    pub fn read<T: Decodable>(&mut self) -> DecodeResult<T> {
        Decodable::decode(self)
    }
}

impl<'a> Decoder for Reader<'a> {
    type Error = DecoderError;

    fn read_nil(&mut self) -> DecodeResult<()> {
        unimplemented!()
    }

    fn read_bool(&mut self) -> DecodeResult<bool> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| bool_decode(self, t))
    }

    fn read_i64(&mut self) -> DecodeResult<i64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| i64_decode(self, t))
    }

    fn read_u64(&mut self) -> DecodeResult<u64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| u64_decode(self, t))
    }

    fn read_f32(&mut self) -> DecodeResult<f32> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| f32_decode(self, t))
    }

    fn read_f64(&mut self) -> DecodeResult<f64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| f64_decode(self, t))
    }

    fn read_char(&mut self) -> DecodeResult<char> {
        unimplemented!()
    }

    fn read_string_without_tag(&mut self) -> DecodeResult<String> {
        // todo: set reader ref
        self.byte_reader.read_string().map_err(|e| DecoderError::ParserError(e))
    }

    fn read_string(&mut self) -> DecodeResult<String> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| string_decode(self, t))
    }

    fn read_bytes(&mut self) -> DecodeResult<Bytes> {
        unimplemented!()
    }

    fn read_option<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnMut(&mut Reader<'a>, bool) -> DecodeResult<T> {
        unimplemented!()
    }

    fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Reader<'a>, usize) -> DecodeResult<T> {
        unimplemented!()
    }

    fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T>
        where F: FnOnce(&mut Reader<'a>, usize) -> DecodeResult<T>
    {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| map_decode(self, t, |d, len| f(d, len)))
    }
}

fn tag_to_str(tag: u8) -> Result<&'static str, DecoderError> {
    match tag {
        b'0'...b'9' | TAG_INTEGER => Ok("i32"),
        TAG_LONG => Ok("big int"),
        TAG_DOUBLE => Ok("f64"),
        TAG_NULL => Ok("nil"),
        TAG_EMPTY => Ok("empty string"),
        TAG_TRUE => Ok("true"),
        TAG_FALSE => Ok("false"),
        TAG_NAN => Ok("NaN"),
        TAG_INFINITY => Ok("Infinity"),
        TAG_DATE | TAG_TIME => Ok("time"),
        TAG_BYTES => Ok("bytes"),
        TAG_UTF8_CHAR | TAG_STRING => Ok("string"),
        TAG_GUID => Ok("GUID"),
        TAG_LIST => Ok("slice"),
        TAG_MAP => Ok("map"),
        TAG_CLASS | TAG_OBJECT => Ok("struct"),
        TAG_REF => Ok("reference"),
        _ => Err(DecoderError::UnexpectedTag(tag, None))
    }
}

pub fn cast_error(tag: u8, dst_type: &'static str) -> DecoderError {
    tag_to_str(tag)
        .map(|src_type| DecoderError::CastError(src_type, dst_type))
        .unwrap_or_else(|e| e)
}

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

    use std::collections::HashMap;

    #[bench]
    fn benchmark_unserialize_bool(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize(&true).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<bool>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_i64(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize(&12345).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<i64>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_str(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize("你好，🇨🇳").bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<String>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_map(b: &mut Bencher) {
        let mut map = HashMap::new();
        map.insert("name", "Tom");
        map.insert("国家", "🇨🇳");
        let bytes = Writer::new(true).serialize(&map).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<HashMap<String, String>>().unwrap();
        });
    }
}
<commit_msg>Added unserialize bool test.<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/reader.rs                                           *
 *                                                        *
 * hprose reader for Rust.                                *
 *                                                        *
 * LastModified: Sep 24, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

extern crate test;

use super::tags::*;
use super::*;

use super::bool_decoder::bool_decode;
use super::i64_decoder::i64_decode;
use super::u64_decoder::u64_decode;
use super::f32_decoder::f32_decode;
use super::f64_decoder::f64_decode;
use super::string_decoder::string_decode;
use super::map_decoder::map_decode;

use std::fmt;
use std::f64;
use std::str;

/// A set of errors that can occur decoding byte slice
#[derive(Clone, PartialEq, Debug)]
pub enum DecoderError {
    ParserError(ParserError),
    CastError(&'static str, &'static str),
    UnexpectedTag(u8, Option<Bytes>)
}

impl fmt::Display for DecoderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DecoderError::CastError(src_type, dst_type) => write!(f, "can't convert {} to {}", src_type, dst_type),
            DecoderError::UnexpectedTag(tag, ref expect_tags_option) => {
                match *expect_tags_option {
                    // todo: format tag as 'c'(0xdd)
                    Some(ref expect_tags) => write!(f, "Tag '{:?}' expected, but '{}' found in stream", expect_tags, tag),
                    None => write!(f, "Unexpected serialize tag '{}' in stream", tag)
                }
            },
            _ => fmt::Debug::fmt(self, f)
        }
    }
}

pub type DecodeResult<T> = Result<T, DecoderError>;

/// Reader is a fine-grained operation struct for Hprose unserialization
pub struct Reader<'a> {
    pub byte_reader: ByteReader<'a>
}

impl<'a> Reader<'a> {
    #[inline]
    pub fn new(buf: &'a [u8], simple: bool) -> Reader<'a> {
        Reader {
            byte_reader: ByteReader::new(buf)
        }
    }

    #[inline]
    pub fn unserialize<T: Decodable>(&mut self) -> DecodeResult<T> {
        self.read()
    }

    #[inline]
    pub fn read<T: Decodable>(&mut self) -> DecodeResult<T> {
        Decodable::decode(self)
    }
}

impl<'a> Decoder for Reader<'a> {
    type Error = DecoderError;

    fn read_nil(&mut self) -> DecodeResult<()> {
        unimplemented!()
    }

    fn read_bool(&mut self) -> DecodeResult<bool> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| bool_decode(self, t))
    }

    fn read_i64(&mut self) -> DecodeResult<i64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| i64_decode(self, t))
    }

    fn read_u64(&mut self) -> DecodeResult<u64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| u64_decode(self, t))
    }

    fn read_f32(&mut self) -> DecodeResult<f32> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| f32_decode(self, t))
    }

    fn read_f64(&mut self) -> DecodeResult<f64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| f64_decode(self, t))
    }

    fn read_char(&mut self) -> DecodeResult<char> {
        unimplemented!()
    }

    fn read_string_without_tag(&mut self) -> DecodeResult<String> {
        // todo: set reader ref
        self.byte_reader.read_string().map_err(|e| DecoderError::ParserError(e))
    }

    fn read_string(&mut self) -> DecodeResult<String> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| string_decode(self, t))
    }

    fn read_bytes(&mut self) -> DecodeResult<Bytes> {
        unimplemented!()
    }

    fn read_option<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnMut(&mut Reader<'a>, bool) -> DecodeResult<T> {
        unimplemented!()
    }

    fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Reader<'a>, usize) -> DecodeResult<T> {
        unimplemented!()
    }

    fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T>
        where F: FnOnce(&mut Reader<'a>, usize) -> DecodeResult<T>
    {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| map_decode(self, t, |d, len| f(d, len)))
    }
}

fn tag_to_str(tag: u8) -> Result<&'static str, DecoderError> {
    match tag {
        b'0'...b'9' | TAG_INTEGER => Ok("i32"),
        TAG_LONG => Ok("big int"),
        TAG_DOUBLE => Ok("f64"),
        TAG_NULL => Ok("nil"),
        TAG_EMPTY => Ok("empty string"),
        TAG_TRUE => Ok("true"),
        TAG_FALSE => Ok("false"),
        TAG_NAN => Ok("NaN"),
        TAG_INFINITY => Ok("Infinity"),
        TAG_DATE | TAG_TIME => Ok("time"),
        TAG_BYTES => Ok("bytes"),
        TAG_UTF8_CHAR | TAG_STRING => Ok("string"),
        TAG_GUID => Ok("GUID"),
        TAG_LIST => Ok("slice"),
        TAG_MAP => Ok("map"),
        TAG_CLASS | TAG_OBJECT => Ok("struct"),
        TAG_REF => Ok("reference"),
        _ => Err(DecoderError::UnexpectedTag(tag, None))
    }
}

pub fn cast_error(tag: u8, dst_type: &'static str) -> DecoderError {
    tag_to_str(tag)
        .map(|src_type| DecoderError::CastError(src_type, dst_type))
        .unwrap_or_else(|e| e)
}

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

    use std::collections::HashMap;

    #[test]
    fn test_unserialize_bool() {
        let true_value = "true";
        let mut w = Writer::new(false);
        w.serialize(&true)
            .serialize(&false)
            .serialize(&())
            .serialize(&"")
            .serialize(&0)
            .serialize(&1)
            .serialize(&9)
            .serialize(&100)
            .serialize(&100000000000000)
            .serialize(&0.0)
            .serialize(&"t")
            .serialize(&"f")
            .serialize(&true_value)
            .serialize(&"false")
            .serialize(&true_value);
        let results = [true, false, false, false, false, true, true, true, true, false, true, false, true, false, true];
        let bytes = w.bytes();
        let mut r = Reader::new(&bytes, false);
        for result in &results {
            assert_eq!(r.unserialize::<bool>(), Ok(*result));
        }
    }

    #[bench]
    fn benchmark_unserialize_bool(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize(&true).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<bool>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_i64(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize(&12345).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<i64>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_str(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize("你好，🇨🇳").bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<String>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_map(b: &mut Bencher) {
        let mut map = HashMap::new();
        map.insert("name", "Tom");
        map.insert("国家", "🇨🇳");
        let bytes = Writer::new(true).serialize(&map).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<HashMap<String, String>>().unwrap();
        });
    }
}
<|endoftext|>


<commit_before>trait Parser<T, E> {
    fn next(&mut self) -> Option<T>;
    fn preview(&self) -> Option<&T>;
    fn current_pos(&self) -> (i32, i32);
    fn error<S: Into<String>>(&self, message: S) -> E;
}

macro_rules! next {
    ($p:expr) => {
        match $p.next() {
            Some(x) => x,
            None => return Err($p.error("unexpected eof")),
        }
    }
}

macro_rules! predicate {
    ($p:expr, $pred:expr) => {{
        let x = next!($p);
        if $pred(x) {
            x
        } else {
            return Err($p.error(format!("unexpected token {}", x)));
        }
    }}
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::vec_deque::VecDeque;

    struct TP {
        input: VecDeque<i32>,
    }

    impl TP {
        fn new(input: &[i32]) -> TP {
            TP { input: VecDeque::from(input.to_vec()) }
        }
    }

    impl Parser<i32, String> for TP {
        fn next(&mut self) -> Option<i32> {
            self.input.pop_front()
        }

        fn preview(&self) -> Option<&i32> {
            self.input.front()
        }

        fn current_pos(&self) -> (i32, i32) {
            (0, 0)
        }

        fn error<S: Into<String>>(&self, message: S) -> String {
            message.into()
        }
    }

    macro_rules! with_res {
        (test $i:ident, $b:block) => {
            #[test]
            fn $i() {
                let result = || {
                    $b;
                    Ok(())
                };
                result().unwrap()
            }
        };
        (panic $e:expr, $i:ident, $b:block) => {
            #[test]
            #[should_panic(expected = $e)]
            fn $i() {
                let result = || {
                    $b;
                    Ok(())
                };
                result().unwrap()
            }
        };
    }

    with_res!(test next_success, {
        let mut p = TP::new(&[1, 2, 3]);
        assert_eq!(next!(p), 1);
        assert_eq!(next!(p), 2);
        assert_eq!(next!(p), 3);
    });

    with_res!(panic "unexpected eof", next_fail_empty, {
        let mut p = TP::new(&[]);
        assert_eq!(next!(p), 1);
    });

    with_res!(test predicate_success, {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(predicate!(p, |x| x % 2 == 0), 2);
        assert_eq!(predicate!(p, |x| x % 2 == 0), 4);
        assert_eq!(predicate!(p, |x| x % 2 == 0), 6);
    });

    with_res!(panic "unexpected eof", predicate_fail_empty, {
        let mut p = TP::new(&[]);
        assert_eq!(predicate!(p, |x| x % 2 == 0), 2);
    });

    with_res!(panic "unexpected token 3", predicate_fail_not_satisfy, {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(predicate!(p, |x| x % 2 == 0), 3);
    });
}
<commit_msg>Implement atom combinator<commit_after>trait Parser<T, E> {
    fn next(&mut self) -> Option<T>;
    fn preview(&self) -> Option<&T>;
    fn current_pos(&self) -> (i32, i32);
    fn error<S: Into<String>>(&self, message: S) -> E;
}

macro_rules! next {
    ($p:expr) => {
        match $p.next() {
            Some(x) => x,
            None => return Err($p.error("unexpected eof")),
        }
    }
}

macro_rules! predicate {
    ($p:expr, $pred:expr) => {{
        let x = next!($p);
        if $pred(x) {
            x
        } else {
            return Err($p.error(format!("unexpected token {}", x)));
        }
    }}
}

macro_rules! atom {
    ($p:expr, $expected:expr) => {{
        let x = next!($p);
        if x == $expected {
            x
        } else {
            return Err(
                $p.error(format!("unexpected token {}, expected {}", x, $expected))
            );
        }
    }}
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::vec_deque::VecDeque;

    struct TP {
        input: VecDeque<i32>,
    }

    impl TP {
        fn new(input: &[i32]) -> TP {
            TP { input: VecDeque::from(input.to_vec()) }
        }
    }

    impl Parser<i32, String> for TP {
        fn next(&mut self) -> Option<i32> {
            self.input.pop_front()
        }

        fn preview(&self) -> Option<&i32> {
            self.input.front()
        }

        fn current_pos(&self) -> (i32, i32) {
            (0, 0)
        }

        fn error<S: Into<String>>(&self, message: S) -> String {
            message.into()
        }
    }

    macro_rules! with_res {
        (test $i:ident, $b:block) => {
            #[test]
            fn $i() {
                let result = || {
                    $b;
                    Ok(())
                };
                result().unwrap()
            }
        };
        (panic $e:expr, $i:ident, $b:block) => {
            #[test]
            #[should_panic(expected = $e)]
            fn $i() {
                let result = || {
                    $b;
                    Ok(())
                };
                result().unwrap()
            }
        };
    }

    with_res!(test next_success, {
        let mut p = TP::new(&[1, 2, 3]);
        assert_eq!(next!(p), 1);
        assert_eq!(next!(p), 2);
        assert_eq!(next!(p), 3);
    });

    with_res!(panic "unexpected eof", next_fail_empty, {
        let mut p = TP::new(&[]);
        assert_eq!(next!(p), 1);
    });

    with_res!(test predicate_success, {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(predicate!(p, |x| x % 2 == 0), 2);
        assert_eq!(predicate!(p, |x| x % 2 == 0), 4);
        assert_eq!(predicate!(p, |x| x % 2 == 0), 6);
    });

    with_res!(panic "unexpected eof", predicate_fail_empty, {
        let mut p = TP::new(&[]);
        assert_eq!(predicate!(p, |x| x % 2 == 0), 2);
    });

    with_res!(panic "unexpected token 3", predicate_fail_not_satisfy, {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(predicate!(p, |x| x % 2 == 0), 3);
    });

    with_res!(test atom_success, {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(atom!(p, 2), 2);
        assert_eq!(atom!(p, 4), 4);
        assert_eq!(atom!(p, 6), 6);
    });

    with_res!(panic "unexpected eof", atom_fail_empty, {
        let mut p = TP::new(&[]);
        assert_eq!(atom!(p, 2), 2);
    });

    with_res!(panic "unexpected token 5, expected 4", atom_fail_not_expected, {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(atom!(p, 3), 3);
        assert_eq!(atom!(p, 4), 4);
    });
}
<|endoftext|>


<commit_before>use std::io::Write;

/// A P-Data value writer.
///
/// This exposes an API to iteratively construct and send Data messages
/// to another node.
/// Using this as a [standard writer](std::io::Write)
/// will automatically split the incoming bytes
/// into separate PDUs if they do not fit in a single one.
///
/// Use an association's `send_pdata` method
/// to create a new P-Data value writer.
pub struct PDataWriter<W: Write> {
    buffer: Vec<u8>,
    stream: W,
    presentation_context_id: u8,
    max_data_length: u32,
}

impl<W> PDataWriter<W>
where
    W: Write,
{
    /// Construct a new P-Data value writer.
    pub(crate) fn new(stream: W, presentation_context_id: u8, max_pdu_length: u32) -> Self {
        let max_data_length = calculate_max_data_len_single(max_pdu_length);
        PDataWriter {
            stream,
            presentation_context_id,
            max_data_length,
            buffer: Vec::with_capacity(max_data_length as usize),
        }
    }

    /// Send the header of a single P-Data PDU,
    /// containing a single data fragment.
    fn send_pdata_header(&mut self, data_len: u32, is_last: bool) -> std::io::Result<()> {
        let mut message_header = 0x00;
        if is_last {
            message_header |= 0x02;
        }

        let pdu_len_bytes = (data_len + 2 + 4).to_be_bytes();
        let data_len_bytes = (data_len + 2).to_be_bytes();
        let header = [
            // PDU-type + reserved byte
            0x04,
            0x00,
            // full PDU length
            pdu_len_bytes[0],
            pdu_len_bytes[1],
            pdu_len_bytes[2],
            pdu_len_bytes[3],
            // presentation data length (data + 2 properties below)
            data_len_bytes[0],
            data_len_bytes[1],
            data_len_bytes[2],
            data_len_bytes[3],
            // presentation context id
            self.presentation_context_id,
            // message control header
            message_header,
        ];

        self.stream.write_all(&header)
    }

    fn finish(&mut self) -> std::io::Result<()> {
        self.dispatch_excess_data()?;
        if !self.buffer.is_empty() {
            // send last PDU
            self.send_pdata_header(self.buffer.len() as u32, true)?;
            self.stream.write_all(&self.buffer[..])?;
            self.buffer.clear();
        }
        Ok(())
    }

    fn dispatch_excess_data(&mut self) -> std::io::Result<()> {
        while self.buffer.len() > self.max_data_length as usize {
            // send PDU now
            self.send_pdata_header(self.max_data_length, false)?;
            let data = &self.buffer[0..self.max_data_length as usize];
            self.stream.write_all(data)?;

            // shift the remaining contents to the beginning of the buffer
            let (p1, p2) = (&mut self.buffer[..]).split_at_mut(self.max_data_length as usize);
            for (e1, e2) in std::iter::Iterator::zip(p1.iter_mut(), p2.iter()) {
                *e1 = *e2;
            }
            self.buffer
                .truncate(self.buffer.len() - self.max_data_length as usize);
        }
        Ok(())
    }
}

impl<W> Write for PDataWriter<W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.buffer.extend(buf);
        self.dispatch_excess_data()?;
        Ok(buf.len())
    }

    fn flush(&mut self) -> std::io::Result<()> {
        // do nothing
        Ok(())
    }
}

impl<W> Drop for PDataWriter<W>
where
    W: Write,
{
    fn drop(&mut self) {
        let _ = self.finish();
    }
}

/// Determine the maximum length of actual data
/// when encapsulated in a PDU with the given length property.
/// Does not account for the first 2 bytes (type + reserved).
#[inline]
fn calculate_max_data_len_single(pdu_len: u32) -> u32 {
    pdu_len
    // data length
    - 4
    // control header
    - 2
}

#[cfg(test)]
mod tests {
    use std::io::Write;

    use crate::pdu::PDataValueType;
    use crate::pdu::Pdu;
    use crate::pdu::{read_pdu, reader::MINIMUM_PDU_SIZE};

    use super::PDataWriter;

    #[test]
    fn test_write_pdata_and_finish() {
        let presentation_context_id = 12;

        let mut buf = Vec::new();
        {
            let mut writer = PDataWriter::new(&mut buf, presentation_context_id, MINIMUM_PDU_SIZE);
            writer.write_all(&(0..64).collect::<Vec<u8>>()).unwrap();
            writer.finish().unwrap();
        }

        let mut cursor = &buf[..];
        let same_pdu = read_pdu(&mut cursor, MINIMUM_PDU_SIZE).unwrap();

        // concatenate data chunks, compare with all data

        match same_pdu {
            Pdu::PData { data: data_1 } => {
                let data_1 = &data_1[0];

                // check that this PDU is consistent
                assert_eq!(data_1.value_type, PDataValueType::Data);
                assert_eq!(data_1.presentation_context_id, presentation_context_id);
                assert_eq!(data_1.data.len(), 64);
                assert_eq!(data_1.data, (0..64).collect::<Vec<u8>>());
            }
            pdu => panic!("Expected PData, got {:?}", pdu),
        }

        assert_eq!(cursor.len(), 0);
    }

    #[test]
    fn test_write_large_pdata_and_finish() {
        let presentation_context_id = 32;

        let my_data: Vec<_> = (0..6000).map(|x| x as u8).collect();
        assert_eq!(my_data.len(), 6000);

        let mut buf = Vec::new();
        {
            let mut writer = PDataWriter::new(&mut buf, presentation_context_id, MINIMUM_PDU_SIZE);
            writer.write_all(&my_data).unwrap();
            writer.finish().unwrap();
        }

        let mut cursor = &buf[..];
        let same_pdu_1 = read_pdu(&mut cursor, MINIMUM_PDU_SIZE).unwrap();
        let same_pdu_2 = read_pdu(&mut cursor, MINIMUM_PDU_SIZE).unwrap();

        // concatenate data chunks, compare with all data

        match (same_pdu_1, same_pdu_2) {
            (Pdu::PData { data: data_1 }, Pdu::PData { data: data_2 }) => {
                let data_1 = &data_1[0];
                let data_2 = &data_2[0];

                // check that these two PDUs are consistent
                assert_eq!(data_1.value_type, PDataValueType::Data);
                assert_eq!(data_2.value_type, PDataValueType::Data);
                assert_eq!(data_1.presentation_context_id, presentation_context_id);
                assert_eq!(data_2.presentation_context_id, presentation_context_id);
                assert_eq!(data_1.data.len() + data_2.data.len(), 6000);

                let data_1 = &data_1.data;
                let data_2 = &data_2.data;

                let mut all_data: Vec<u8> = Vec::new();
                all_data.extend(data_1);
                all_data.extend(data_2);
                assert_eq!(all_data, my_data);
            }
            x => panic!("Expected two PDatas, got {:?}", x),
        }

        assert_eq!(cursor.len(), 0);
    }
}
<commit_msg>[ul] add must_use to PDataWriter<commit_after>use std::io::Write;

/// A P-Data value writer.
///
/// This exposes an API to iteratively construct and send Data messages
/// to another node.
/// Using this as a [standard writer](std::io::Write)
/// will automatically split the incoming bytes
/// into separate PDUs if they do not fit in a single one.
///
/// Use an association's `send_pdata` method
/// to create a new P-Data value writer.
#[must_use]
pub struct PDataWriter<W: Write> {
    buffer: Vec<u8>,
    stream: W,
    presentation_context_id: u8,
    max_data_length: u32,
}

impl<W> PDataWriter<W>
where
    W: Write,
{
    /// Construct a new P-Data value writer.
    pub(crate) fn new(stream: W, presentation_context_id: u8, max_pdu_length: u32) -> Self {
        let max_data_length = calculate_max_data_len_single(max_pdu_length);
        PDataWriter {
            stream,
            presentation_context_id,
            max_data_length,
            buffer: Vec::with_capacity(max_data_length as usize),
        }
    }

    /// Send the header of a single P-Data PDU,
    /// containing a single data fragment.
    fn send_pdata_header(&mut self, data_len: u32, is_last: bool) -> std::io::Result<()> {
        let mut message_header = 0x00;
        if is_last {
            message_header |= 0x02;
        }

        let pdu_len_bytes = (data_len + 2 + 4).to_be_bytes();
        let data_len_bytes = (data_len + 2).to_be_bytes();
        let header = [
            // PDU-type + reserved byte
            0x04,
            0x00,
            // full PDU length
            pdu_len_bytes[0],
            pdu_len_bytes[1],
            pdu_len_bytes[2],
            pdu_len_bytes[3],
            // presentation data length (data + 2 properties below)
            data_len_bytes[0],
            data_len_bytes[1],
            data_len_bytes[2],
            data_len_bytes[3],
            // presentation context id
            self.presentation_context_id,
            // message control header
            message_header,
        ];

        self.stream.write_all(&header)
    }

    fn finish(&mut self) -> std::io::Result<()> {
        self.dispatch_excess_data()?;
        if !self.buffer.is_empty() {
            // send last PDU
            self.send_pdata_header(self.buffer.len() as u32, true)?;
            self.stream.write_all(&self.buffer[..])?;
            self.buffer.clear();
        }
        Ok(())
    }

    fn dispatch_excess_data(&mut self) -> std::io::Result<()> {
        while self.buffer.len() > self.max_data_length as usize {
            // send PDU now
            self.send_pdata_header(self.max_data_length, false)?;
            let data = &self.buffer[0..self.max_data_length as usize];
            self.stream.write_all(data)?;

            // shift the remaining contents to the beginning of the buffer
            let (p1, p2) = (&mut self.buffer[..]).split_at_mut(self.max_data_length as usize);
            for (e1, e2) in std::iter::Iterator::zip(p1.iter_mut(), p2.iter()) {
                *e1 = *e2;
            }
            self.buffer
                .truncate(self.buffer.len() - self.max_data_length as usize);
        }
        Ok(())
    }
}

impl<W> Write for PDataWriter<W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.buffer.extend(buf);
        self.dispatch_excess_data()?;
        Ok(buf.len())
    }

    fn flush(&mut self) -> std::io::Result<()> {
        // do nothing
        Ok(())
    }
}

impl<W> Drop for PDataWriter<W>
where
    W: Write,
{
    fn drop(&mut self) {
        let _ = self.finish();
    }
}

/// Determine the maximum length of actual data
/// when encapsulated in a PDU with the given length property.
/// Does not account for the first 2 bytes (type + reserved).
#[inline]
fn calculate_max_data_len_single(pdu_len: u32) -> u32 {
    pdu_len
    // data length
    - 4
    // control header
    - 2
}

#[cfg(test)]
mod tests {
    use std::io::Write;

    use crate::pdu::PDataValueType;
    use crate::pdu::Pdu;
    use crate::pdu::{read_pdu, reader::MINIMUM_PDU_SIZE};

    use super::PDataWriter;

    #[test]
    fn test_write_pdata_and_finish() {
        let presentation_context_id = 12;

        let mut buf = Vec::new();
        {
            let mut writer = PDataWriter::new(&mut buf, presentation_context_id, MINIMUM_PDU_SIZE);
            writer.write_all(&(0..64).collect::<Vec<u8>>()).unwrap();
            writer.finish().unwrap();
        }

        let mut cursor = &buf[..];
        let same_pdu = read_pdu(&mut cursor, MINIMUM_PDU_SIZE).unwrap();

        // concatenate data chunks, compare with all data

        match same_pdu {
            Pdu::PData { data: data_1 } => {
                let data_1 = &data_1[0];

                // check that this PDU is consistent
                assert_eq!(data_1.value_type, PDataValueType::Data);
                assert_eq!(data_1.presentation_context_id, presentation_context_id);
                assert_eq!(data_1.data.len(), 64);
                assert_eq!(data_1.data, (0..64).collect::<Vec<u8>>());
            }
            pdu => panic!("Expected PData, got {:?}", pdu),
        }

        assert_eq!(cursor.len(), 0);
    }

    #[test]
    fn test_write_large_pdata_and_finish() {
        let presentation_context_id = 32;

        let my_data: Vec<_> = (0..6000).map(|x| x as u8).collect();
        assert_eq!(my_data.len(), 6000);

        let mut buf = Vec::new();
        {
            let mut writer = PDataWriter::new(&mut buf, presentation_context_id, MINIMUM_PDU_SIZE);
            writer.write_all(&my_data).unwrap();
            writer.finish().unwrap();
        }

        let mut cursor = &buf[..];
        let same_pdu_1 = read_pdu(&mut cursor, MINIMUM_PDU_SIZE).unwrap();
        let same_pdu_2 = read_pdu(&mut cursor, MINIMUM_PDU_SIZE).unwrap();

        // concatenate data chunks, compare with all data

        match (same_pdu_1, same_pdu_2) {
            (Pdu::PData { data: data_1 }, Pdu::PData { data: data_2 }) => {
                let data_1 = &data_1[0];
                let data_2 = &data_2[0];

                // check that these two PDUs are consistent
                assert_eq!(data_1.value_type, PDataValueType::Data);
                assert_eq!(data_2.value_type, PDataValueType::Data);
                assert_eq!(data_1.presentation_context_id, presentation_context_id);
                assert_eq!(data_2.presentation_context_id, presentation_context_id);
                assert_eq!(data_1.data.len() + data_2.data.len(), 6000);

                let data_1 = &data_1.data;
                let data_2 = &data_2.data;

                let mut all_data: Vec<u8> = Vec::new();
                all_data.extend(data_1);
                all_data.extend(data_2);
                assert_eq!(all_data, my_data);
            }
            x => panic!("Expected two PDatas, got {:?}", x),
        }

        assert_eq!(cursor.len(), 0);
    }
}
<|endoftext|>


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

//! For each transaction the VM executes, the VM will output a `WriteSet` that contains each access
//! path it updates. For each access path, the VM can either give its new value or delete it.

use crate::access_path::AccessPath;
use canonical_serialization::{
    CanonicalDeserialize, CanonicalDeserializer, CanonicalSerialize, CanonicalSerializer,
};
use failure::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum WriteOp {
    Value(Vec<u8>),
    Deletion,
}

impl WriteOp {
    #[inline]
    pub fn is_value(&self) -> bool {
        match self {
            WriteOp::Value(_) => true,
            WriteOp::Deletion => false,
        }
    }

    #[inline]
    pub fn is_deletion(&self) -> bool {
        match self {
            WriteOp::Deletion => true,
            WriteOp::Value(_) => false,
        }
    }
}

impl std::fmt::Debug for WriteOp {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            WriteOp::Value(value) => write!(f, "Value({})", String::from_utf8_lossy(value)),
            WriteOp::Deletion => write!(f, "Deletion"),
        }
    }
}

impl CanonicalSerialize for WriteOp {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        match self {
            WriteOp::Deletion => serializer.encode_u32(WriteOpType::Deletion as u32)?,
            WriteOp::Value(value) => {
                serializer.encode_u32(WriteOpType::Value as u32)?;
                serializer.encode_vec(value)?
            }
        };
        Ok(())
    }
}

impl CanonicalDeserialize for WriteOp {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let decoded_write_op_type = deserializer.decode_u32()?;
        let write_op_type = WriteOpType::from_u32(decoded_write_op_type);
        match write_op_type {
            Some(WriteOpType::Deletion) => Ok(WriteOp::Deletion),
            Some(WriteOpType::Value) => Ok(WriteOp::Value(deserializer.decode_vec()?)),
            None => Err(format_err!(
                "ParseError: Unable to decode WriteOpType, found {}",
                decoded_write_op_type
            )),
        }
    }
}

#[derive(Clone, Debug, Hash, Eq, PartialEq)]
enum WriteOpType {
    Deletion = 0,
    Value = 1,
}

impl WriteOpType {
    fn from_u32(value: u32) -> Option<WriteOpType> {
        match value {
            0 => Some(WriteOpType::Deletion),
            1 => Some(WriteOpType::Value),
            _ => None,
        }
    }
}

/// `WriteSet` contains all access paths that one transaction modifies. Each of them is a `WriteOp`
/// where `Value(val)` means that serialized representation should be updated to `val`, and
/// `Deletion` means that we are going to delete this access path.
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct WriteSet(WriteSetMut);

impl WriteSet {
    #[inline]
    pub fn len(&self) -> usize {
        self.0.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> ::std::slice::Iter<'a, (AccessPath, WriteOp)> {
        self.into_iter()
    }

    #[inline]
    pub fn into_mut(self) -> WriteSetMut {
        self.0
    }
}

/// A mutable version of `WriteSet`.
///
/// This is separate because it goes through validation before becoming an immutable `WriteSet`.
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct WriteSetMut {
    write_set: Vec<(AccessPath, WriteOp)>,
}

impl WriteSetMut {
    pub fn new(write_set: Vec<(AccessPath, WriteOp)>) -> Self {
        Self { write_set }
    }

    pub fn push(&mut self, item: (AccessPath, WriteOp)) {
        self.write_set.push(item);
    }

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

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.write_set.is_empty()
    }

    pub fn freeze(self) -> Result<WriteSet> {
        // TODO: add structural validation
        Ok(WriteSet(self))
    }
}

impl CanonicalSerialize for WriteSet {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        serializer.encode_vec(&self.0.write_set)?;
        Ok(())
    }
}

impl CanonicalDeserialize for WriteSet {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let write_set = deserializer.decode_vec::<(AccessPath, WriteOp)>()?;
        WriteSetMut::new(write_set).freeze()
    }
}

impl ::std::iter::FromIterator<(AccessPath, WriteOp)> for WriteSetMut {
    fn from_iter<I: IntoIterator<Item = (AccessPath, WriteOp)>>(iter: I) -> Self {
        let mut ws = WriteSetMut::default();
        for write in iter {
            ws.push((write.0, write.1));
        }
        ws
    }
}

impl<'a> IntoIterator for &'a WriteSet {
    type Item = &'a (AccessPath, WriteOp);
    type IntoIter = ::std::slice::Iter<'a, (AccessPath, WriteOp)>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.write_set.iter()
    }
}

impl ::std::iter::IntoIterator for WriteSet {
    type Item = (AccessPath, WriteOp);
    type IntoIter = ::std::vec::IntoIter<(AccessPath, WriteOp)>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.write_set.into_iter()
    }
}
<commit_msg>Removing is_value from types/src/write_set.rs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! For each transaction the VM executes, the VM will output a `WriteSet` that contains each access
//! path it updates. For each access path, the VM can either give its new value or delete it.

use crate::access_path::AccessPath;
use canonical_serialization::{
    CanonicalDeserialize, CanonicalDeserializer, CanonicalSerialize, CanonicalSerializer,
};
use failure::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum WriteOp {
    Value(Vec<u8>),
    Deletion,
}

impl WriteOp {
    #[inline]
    pub fn is_deletion(&self) -> bool {
        match self {
            WriteOp::Deletion => true,
            WriteOp::Value(_) => false,
        }
    }
}

impl std::fmt::Debug for WriteOp {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            WriteOp::Value(value) => write!(f, "Value({})", String::from_utf8_lossy(value)),
            WriteOp::Deletion => write!(f, "Deletion"),
        }
    }
}

impl CanonicalSerialize for WriteOp {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        match self {
            WriteOp::Deletion => serializer.encode_u32(WriteOpType::Deletion as u32)?,
            WriteOp::Value(value) => {
                serializer.encode_u32(WriteOpType::Value as u32)?;
                serializer.encode_vec(value)?
            }
        };
        Ok(())
    }
}

impl CanonicalDeserialize for WriteOp {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let decoded_write_op_type = deserializer.decode_u32()?;
        let write_op_type = WriteOpType::from_u32(decoded_write_op_type);
        match write_op_type {
            Some(WriteOpType::Deletion) => Ok(WriteOp::Deletion),
            Some(WriteOpType::Value) => Ok(WriteOp::Value(deserializer.decode_vec()?)),
            None => Err(format_err!(
                "ParseError: Unable to decode WriteOpType, found {}",
                decoded_write_op_type
            )),
        }
    }
}

#[derive(Clone, Debug, Hash, Eq, PartialEq)]
enum WriteOpType {
    Deletion = 0,
    Value = 1,
}

impl WriteOpType {
    fn from_u32(value: u32) -> Option<WriteOpType> {
        match value {
            0 => Some(WriteOpType::Deletion),
            1 => Some(WriteOpType::Value),
            _ => None,
        }
    }
}

/// `WriteSet` contains all access paths that one transaction modifies. Each of them is a `WriteOp`
/// where `Value(val)` means that serialized representation should be updated to `val`, and
/// `Deletion` means that we are going to delete this access path.
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct WriteSet(WriteSetMut);

impl WriteSet {
    #[inline]
    pub fn len(&self) -> usize {
        self.0.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> ::std::slice::Iter<'a, (AccessPath, WriteOp)> {
        self.into_iter()
    }

    #[inline]
    pub fn into_mut(self) -> WriteSetMut {
        self.0
    }
}

/// A mutable version of `WriteSet`.
///
/// This is separate because it goes through validation before becoming an immutable `WriteSet`.
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct WriteSetMut {
    write_set: Vec<(AccessPath, WriteOp)>,
}

impl WriteSetMut {
    pub fn new(write_set: Vec<(AccessPath, WriteOp)>) -> Self {
        Self { write_set }
    }

    pub fn push(&mut self, item: (AccessPath, WriteOp)) {
        self.write_set.push(item);
    }

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

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.write_set.is_empty()
    }

    pub fn freeze(self) -> Result<WriteSet> {
        // TODO: add structural validation
        Ok(WriteSet(self))
    }
}

impl CanonicalSerialize for WriteSet {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        serializer.encode_vec(&self.0.write_set)?;
        Ok(())
    }
}

impl CanonicalDeserialize for WriteSet {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let write_set = deserializer.decode_vec::<(AccessPath, WriteOp)>()?;
        WriteSetMut::new(write_set).freeze()
    }
}

impl ::std::iter::FromIterator<(AccessPath, WriteOp)> for WriteSetMut {
    fn from_iter<I: IntoIterator<Item = (AccessPath, WriteOp)>>(iter: I) -> Self {
        let mut ws = WriteSetMut::default();
        for write in iter {
            ws.push((write.0, write.1));
        }
        ws
    }
}

impl<'a> IntoIterator for &'a WriteSet {
    type Item = &'a (AccessPath, WriteOp);
    type IntoIter = ::std::slice::Iter<'a, (AccessPath, WriteOp)>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.write_set.iter()
    }
}

impl ::std::iter::IntoIterator for WriteSet {
    type Item = (AccessPath, WriteOp);
    type IntoIter = ::std::vec::IntoIter<(AccessPath, WriteOp)>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.write_set.into_iter()
    }
}
<|endoftext|>


<commit_before>// Claxon -- A FLAC decoding library in Rust
// Copyright 2017 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

// This file contains a minimal example of using Claxon with Ogg and Hound
// to decode a flac stream inside an ogg container to a wav file. See also
// https://xiph.org/flac/ogg_mapping.html.

extern crate claxon;
extern crate hound;
extern crate ogg;

use std::env;
use std::fs::File;
use std::io;
use std::path::Path;

use claxon::input::ReadBytes;
use claxon::metadata::{StreamInfo, read_metadata_block_with_header};
use hound::{WavSpec, WavWriter};

fn decode_file(fname: &Path) {
    // Create a file to read from. The ogg crate will read "packets" from here.
    let file = File::open(fname).expect("failed to open ogg file");
    let bufread = io::BufReader::new(file);
    let mut preader = ogg::PacketReader::new(bufread);

    // According to the FLAC to Ogg mapping, the first packet contains the
    // streaminfo. It also contains a count of how many metadata packets follow.
    let first_packet = preader.read_packet_expected().expect("failed to read ogg");
    let (streaminfo, header_packets_left) = read_first_packet(&first_packet);

    // Skip over the packets that contain metadata. We do decode the metadata
    // just for demonstration purposes, but then we throw it away.
    for _ in 0..header_packets_left {
        let packet = preader.read_packet_expected().expect("failed to read ogg");
        let mut cursor = io::Cursor::new(&packet.data);
        let _metadata_block = read_metadata_block_with_header(&mut cursor).unwrap();
    }

    // Build a wav writer to write the decoded audio to a wav file.
    let spec = WavSpec {
        channels: streaminfo.channels as u16,
        sample_rate: streaminfo.sample_rate,
        bits_per_sample: streaminfo.bits_per_sample as u16,
        sample_format: hound::SampleFormat::Int,
    };

    let fname_wav = fname.with_extension("wav");
    let opt_wav_writer = WavWriter::create(fname_wav, spec);
    let mut _wav_writer = opt_wav_writer.expect("failed to create wav file");

    // TODO: Actually read audio packets.
}

/// Decode the streaminfo block, and the number of metadata packets that still follow.
fn read_first_packet(packet: &ogg::Packet) -> (StreamInfo, u16) {
    use claxon::metadata::MetadataBlock;

    let mut cursor = io::Cursor::new(&packet.data);

    // The first 7 bytes contain magic values and version info. We don't
    // verify this. A real application should. Because we are using an
    // `io::Cursor`, the IO operation will not fail, so the unwrap is safe.
    cursor.skip(7).unwrap();

    // Next is a 16-bit big-endian number that specifies the number of header
    // packets that follow. Claxon exposes a `ReadBytes` trait that simplifies
    // reading this.
    let header_packets_left = cursor.read_be_u16().unwrap();

    // The 'fLaC' magic signature follows. We don't verify it.
    cursor.skip(4).unwrap();

    // Next is the streaminfo metadata block, which we return.
    match read_metadata_block_with_header(&mut cursor) {
      Ok(MetadataBlock::StreamInfo(si)) => (si, header_packets_left),
      Ok(..) => panic!("expected streaminfo, found other metadata block"),
      Err(err) => panic!("failed to read streaminfo: {:?}", err),
    }
}

fn main() {
    for fname in env::args().skip(1) {
        decode_file(&Path::new(&fname));
    }
}
<commit_msg>Fully implement flac-in-ogg decoding example<commit_after>// Claxon -- A FLAC decoding library in Rust
// Copyright 2017 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

// This file contains a minimal example of using Claxon with Ogg and Hound
// to decode a flac stream inside an ogg container to a wav file. It assumes
// that the ogg file actually contains flac data, this is not verified. See
// also https://xiph.org/flac/ogg_mapping.html for the format.

extern crate claxon;
extern crate hound;
extern crate ogg;

use std::env;
use std::fs::File;
use std::io;
use std::path::Path;

use claxon::input::ReadBytes;
use claxon::metadata::{StreamInfo, read_metadata_block_with_header};
use hound::{WavSpec, WavWriter};

fn decode_file(fname: &Path) {
    // Create a file to read from. The ogg crate will read "packets" from here.
    let file = File::open(fname).expect("failed to open ogg file");
    let bufread = io::BufReader::new(file);
    let mut preader = ogg::PacketReader::new(bufread);

    // According to the FLAC to Ogg mapping, the first packet contains the
    // streaminfo. It also contains a count of how many metadata packets follow.
    let first_packet = preader.read_packet_expected().expect("failed to read ogg");
    let (streaminfo, header_packets_left) = read_first_packet(&first_packet);

    // Skip over the packets that contain metadata. We do decode the metadata
    // just for demonstration purposes, but then we throw it away.
    for _ in 0..header_packets_left {
        let packet = preader.read_packet_expected().expect("failed to read ogg");
        let mut cursor = io::Cursor::new(&packet.data);
        let _metadata_block = read_metadata_block_with_header(&mut cursor).unwrap();
    }

    // Build a wav writer to write the decoded audio to a wav file.
    let spec = WavSpec {
        channels: streaminfo.channels as u16,
        sample_rate: streaminfo.sample_rate,
        bits_per_sample: streaminfo.bits_per_sample as u16,
        sample_format: hound::SampleFormat::Int,
    };

    let fname_wav = fname.with_extension("wav");
    let opt_wav_writer = WavWriter::create(fname_wav, spec);
    let mut wav_writer = opt_wav_writer.expect("failed to create wav file");

    // All the packets that follow contain one flac frame each. Decode those one
    // by one, recycling the buffer.
    let mut buffer = Vec::with_capacity(streaminfo.max_block_size as usize);
    while let Some(packet) = preader.read_packet().expect("failed to read ogg") {
        // Empty packets do occur, skip them. So far I have only observed the
        // final packet to be empty.
        if packet.data.len() == 0 { continue }
        buffer = decode_frame(&packet, buffer, &mut wav_writer);
    }
}

/// Decode the streaminfo block, and the number of metadata packets that still follow.
fn read_first_packet(packet: &ogg::Packet) -> (StreamInfo, u16) {
    use claxon::metadata::MetadataBlock;

    let mut cursor = io::Cursor::new(&packet.data);

    // The first 7 bytes contain magic values and version info. We don't
    // verify this. A real application should. Because we are using an
    // `io::Cursor`, the IO operation will not fail, so the unwrap is safe.
    cursor.skip(7).unwrap();

    // Next is a 16-bit big-endian number that specifies the number of header
    // packets that follow. Claxon exposes a `ReadBytes` trait that simplifies
    // reading this.
    let header_packets_left = cursor.read_be_u16().unwrap();

    // The 'fLaC' magic signature follows. We don't verify it.
    cursor.skip(4).unwrap();

    // Next is the streaminfo metadata block, which we return.
    match read_metadata_block_with_header(&mut cursor) {
      Ok(MetadataBlock::StreamInfo(si)) => (si, header_packets_left),
      Ok(..) => panic!("expected streaminfo, found other metadata block"),
      Err(err) => panic!("failed to read streaminfo: {:?}", err),
    }
}

/// Decode a single frame stored in an ogg packet.
///
/// Takes a buffer to decode into, and returns it again so it can be recycled.
fn decode_frame<W>(packet: &ogg::Packet,
                   buffer: Vec<i32>,
                   wav_writer: &mut WavWriter<W>)
                   -> Vec<i32>
where W: io::Seek + io::Write {
    // The Claxon `FrameReader` takes something that implements `ReadBytes`, it
    // needs a buffer to decode efficiently. The packet stores the bytes in a
    // vec, so wrapping it in an `io::Cursor` works; it implements `ReadBytes`.
    let cursor = io::Cursor::new(&packet.data);

    let mut frame_reader = claxon::frame::FrameReader::new(cursor);

    // TODO There should be a read_next method too that does not tolerate EOF.
    let result = frame_reader.read_next_or_eof(buffer);
    let block = result.expect("failed to decode frame").expect("unexpected EOF");

    // TODO: Here we assume that we are decoding a stereo stream, which is
    // wrong, but very convenient, as there is no interleaved sample iterator
    // for `Block`. One should be added.
    for (sl, sr) in block.stereo_samples() {
        wav_writer.write_sample(sl).expect("failed to write wav file");
        wav_writer.write_sample(sr).expect("failed to write wav file");
    }

    // Give the buffer back so it can be recycled.
    block.into_buffer()
}

fn main() {
    for fname in env::args().skip(1) {
        decode_file(&Path::new(&fname));
    }
}
<|endoftext|>


<commit_before>use std::num::{One, Zero};
use std::rand::{Rand, Rng, RngUtil};
use std::cmp::ApproxEq;
use traits::dim::Dim;
use traits::inv::Inv;
use traits::rotation::{Rotation, Rotate, Rotatable};
use traits::translation::{Translation, Translate, Translatable};
use traits::transformation;
use traits::transformation::{Transformation, Transformable};
use traits::rlmul::{RMul, LMul};
use traits::homogeneous::{ToHomogeneous, FromHomogeneous};
use traits::column::Column;

#[deriving(Eq, ToStr)]
pub struct Transform<M, V>
{
  priv submat   : M,
  priv subtrans : V
}

impl<M, V> Transform<M, V>
{
  #[inline]
  pub fn new(mat: M, trans: V) -> Transform<M, V>
  { Transform { submat: mat, subtrans: trans } }
}

impl<M:Dim, V> Dim for Transform<M, V>
{
  #[inline]
  fn dim() -> uint
  { Dim::dim::<M>() }
}

impl<M: One, V: Zero> One for Transform<M, V>
{
  #[inline]
  fn one() -> Transform<M, V>
  { Transform { submat: One::one(), subtrans: Zero::zero() } }
}

impl<M: Zero, V: Zero> Zero for Transform<M, V>
{
  #[inline]
  fn zero() -> Transform<M, V>
  { Transform { submat: Zero::zero(), subtrans: Zero::zero() } }

  #[inline]
  fn is_zero(&self) -> bool
  { self.submat.is_zero() && self.subtrans.is_zero() }
}

impl<M: RMul<V> + Mul<M, M>, V: Add<V, V>>
Mul<Transform<M, V>, Transform<M, V>> for Transform<M, V>
{
  #[inline]
  fn mul(&self, other: &Transform<M, V>) -> Transform<M, V>
  {
    Transform { submat: self.submat * other.submat,
                subtrans: self.subtrans + self.submat.rmul(&other.subtrans) }
  }
}

impl<M: RMul<V>, V: Add<V, V>> RMul<V> for Transform<M, V>
{
  #[inline]
  fn rmul(&self, other: &V) -> V
  { self.submat.rmul(other) + self.subtrans }
}

impl<M: LMul<V>, V: Add<V, V>> LMul<V> for Transform<M, V>
{
  #[inline]
  fn lmul(&self, other: &V) -> V
  { self.submat.lmul(other) + self.subtrans }
}

impl<M, V: Translation<V>> Translation<V> for Transform<M, V>
{
  #[inline]
  fn translation(&self) -> V
  { self.subtrans.translation() }

  #[inline]
  fn inv_translation(&self) -> V
  { self.subtrans.inv_translation() }

  #[inline]
  fn translate_by(&mut self, t: &V)
  { self.subtrans.translate_by(t) }
}

impl<M: Translate<V>, V, _0> Translate<V> for Transform<M, _0>
{
  #[inline]
  fn translate(&self, v: &V) -> V
  { self.submat.translate(v) }

  #[inline]
  fn inv_translate(&self, v: &V) -> V
  { self.submat.inv_translate(v) }
}

impl<M: Copy, V: Translatable<V, V> + Translation<V>>
Translatable<V, Transform<M, V>> for Transform<M, V>
{
  #[inline]
  fn translated(&self, t: &V) -> Transform<M, V>
  { Transform::new(copy self.submat, self.subtrans.translated(t)) }
}

impl<M: Rotation<AV> + RMul<V> + One,
     V,
     AV>
Rotation<AV> for Transform<M, V>
{
  #[inline]
  fn rotation(&self) -> AV
  { self.submat.rotation() }

  #[inline]
  fn inv_rotation(&self) -> AV
  { self.submat.inv_rotation() }

  #[inline]
  fn rotate_by(&mut self, rot: &AV)
  {
    // FIXME: this does not seem opitmal
    let mut delta = One::one::<M>();
    delta.rotate_by(rot);
    self.submat.rotate_by(rot);
    self.subtrans = delta.rmul(&self.subtrans);
  }
}

impl<M: Rotate<V>, V, _0> Rotate<V> for Transform<M, _0>
{
  #[inline]
  fn rotate(&self, v: &V) -> V
  { self.submat.rotate(v) }

  #[inline]
  fn inv_rotate(&self, v: &V) -> V
  { self.submat.inv_rotate(v) }
}

impl<M: Rotatable<AV, Res> + One,
     Res: Rotation<AV> + RMul<V> + One,
     V,
     AV>
Rotatable<AV, Transform<Res, V>> for Transform<M, V>
{
  #[inline]
  fn rotated(&self, rot: &AV) -> Transform<Res, V>
  {
    // FIXME: this does not seem opitmal
    let delta = One::one::<M>().rotated(rot);

    Transform::new(self.submat.rotated(rot), delta.rmul(&self.subtrans))
  }
}

impl<M: Inv + RMul<V> + Mul<M, M> + Copy, V: Add<V, V> + Neg<V> + Copy>
Transformation<Transform<M, V>> for Transform<M, V>
{
  fn transformation(&self) -> Transform<M, V>
  { copy *self }

  fn inv_transformation(&self) -> Transform<M, V>
  { self.inverse() }

  fn transform_by(&mut self, other: &Transform<M, V>)
  { *self = other * *self; }
}

impl<M: transformation::Transform<V>, V: Add<V, V> + Sub<V, V>>
transformation::Transform<V> for Transform<M, V>
{
  #[inline]
  fn transform_vec(&self, v: &V) -> V
  { self.submat.transform_vec(v) + self.subtrans }

  #[inline]
  fn inv_transform(&self, v: &V) -> V
  { self.submat.inv_transform(&(v - self.subtrans)) }
}

// FIXME: constraints are too restrictive.
// Should be: Transformable<M2, // Transform<Res, V> ...
impl<M: RMul<V> + Mul<M, M> + Inv, V: Add<V, V> + Neg<V>>
Transformable<Transform<M, V>, Transform<M, V>> for Transform<M, V>
{
  fn transformed(&self, t: &Transform<M, V>) -> Transform<M, V>
  { t * *self }
}

impl<M: Copy + Inv + RMul<V>, V: Copy + Neg<V>>
Inv for Transform<M, V>
{
  #[inline]
  fn invert(&mut self)
  {
    self.submat.invert();
    self.subtrans = self.submat.rmul(&-self.subtrans);
  }

  #[inline]
  fn inverse(&self) -> Transform<M, V>
  {
    let mut res = copy *self;

    res.invert();

    res
  }
}

impl<M: ToHomogeneous<M2>, M2: Dim + Column<V>, V: Copy>
ToHomogeneous<M2> for Transform<M, V>
{
  fn to_homogeneous(&self) -> M2
  {
    let mut res = self.submat.to_homogeneous();

    // copy the translation
    let dim = Dim::dim::<M2>();

    res.set_column(dim - 1, copy self.subtrans);

    res
  }
}

impl<M: Column<V> + Dim, M2: FromHomogeneous<M>, V: Copy>
FromHomogeneous<M> for Transform<M2, V>
{
  fn from_homogeneous(m: &M) -> Transform<M2, V>
  {
    Transform::new(FromHomogeneous::from_homogeneous(m),
                   m.column(Dim::dim::<M>() - 1))
  }
}

impl<N: ApproxEq<N>, M:ApproxEq<N>, V:ApproxEq<N>>
ApproxEq<N> for Transform<M, V>
{
  #[inline]
  fn approx_epsilon() -> N
  { ApproxEq::approx_epsilon::<N, N>() }

  #[inline]
  fn approx_eq(&self, other: &Transform<M, V>) -> bool
  {
    self.submat.approx_eq(&other.submat) &&
    self.subtrans.approx_eq(&other.subtrans)
  }

  #[inline]
  fn approx_eq_eps(&self, other: &Transform<M, V>, epsilon: &N) -> bool
  {
    self.submat.approx_eq_eps(&other.submat, epsilon) &&
    self.subtrans.approx_eq_eps(&other.subtrans, epsilon)
  }
}

impl<M: Rand, V: Rand> Rand for Transform<M, V>
{
  #[inline]
  fn rand<R: Rng>(rng: &mut R) -> Transform<M, V>
  { Transform::new(rng.gen(), rng.gen()) }
}
<commit_msg>Add read-only accesse to a Transform subcomponents.<commit_after>use std::num::{One, Zero};
use std::rand::{Rand, Rng, RngUtil};
use std::cmp::ApproxEq;
use traits::dim::Dim;
use traits::inv::Inv;
use traits::rotation::{Rotation, Rotate, Rotatable};
use traits::translation::{Translation, Translate, Translatable};
use traits::transformation;
use traits::transformation::{Transformation, Transformable};
use traits::rlmul::{RMul, LMul};
use traits::homogeneous::{ToHomogeneous, FromHomogeneous};
use traits::column::Column;

#[deriving(Eq, ToStr)]
pub struct Transform<M, V>
{
  priv submat   : M,
  priv subtrans : V
}

impl<M, V> Transform<M, V>
{
  #[inline]
  pub fn new(mat: M, trans: V) -> Transform<M, V>
  { Transform { submat: mat, subtrans: trans } }
}

impl<M: Copy, V: Copy> Transform<M, V>
{
  #[inline]
  pub fn submat(&self) -> M
  { copy self.submat }

  #[inline]
  pub fn subtrans(&self) -> V
  { copy self.subtrans }
}

impl<M:Dim, V> Dim for Transform<M, V>
{
  #[inline]
  fn dim() -> uint
  { Dim::dim::<M>() }
}

impl<M: One, V: Zero> One for Transform<M, V>
{
  #[inline]
  fn one() -> Transform<M, V>
  { Transform { submat: One::one(), subtrans: Zero::zero() } }
}

impl<M: Zero, V: Zero> Zero for Transform<M, V>
{
  #[inline]
  fn zero() -> Transform<M, V>
  { Transform { submat: Zero::zero(), subtrans: Zero::zero() } }

  #[inline]
  fn is_zero(&self) -> bool
  { self.submat.is_zero() && self.subtrans.is_zero() }
}

impl<M: RMul<V> + Mul<M, M>, V: Add<V, V>>
Mul<Transform<M, V>, Transform<M, V>> for Transform<M, V>
{
  #[inline]
  fn mul(&self, other: &Transform<M, V>) -> Transform<M, V>
  {
    Transform { submat: self.submat * other.submat,
                subtrans: self.subtrans + self.submat.rmul(&other.subtrans) }
  }
}

impl<M: RMul<V>, V: Add<V, V>> RMul<V> for Transform<M, V>
{
  #[inline]
  fn rmul(&self, other: &V) -> V
  { self.submat.rmul(other) + self.subtrans }
}

impl<M: LMul<V>, V: Add<V, V>> LMul<V> for Transform<M, V>
{
  #[inline]
  fn lmul(&self, other: &V) -> V
  { self.submat.lmul(other) + self.subtrans }
}

impl<M, V: Translation<V>> Translation<V> for Transform<M, V>
{
  #[inline]
  fn translation(&self) -> V
  { self.subtrans.translation() }

  #[inline]
  fn inv_translation(&self) -> V
  { self.subtrans.inv_translation() }

  #[inline]
  fn translate_by(&mut self, t: &V)
  { self.subtrans.translate_by(t) }
}

impl<M: Translate<V>, V, _0> Translate<V> for Transform<M, _0>
{
  #[inline]
  fn translate(&self, v: &V) -> V
  { self.submat.translate(v) }

  #[inline]
  fn inv_translate(&self, v: &V) -> V
  { self.submat.inv_translate(v) }
}

impl<M: Copy, V: Translatable<V, V> + Translation<V>>
Translatable<V, Transform<M, V>> for Transform<M, V>
{
  #[inline]
  fn translated(&self, t: &V) -> Transform<M, V>
  { Transform::new(copy self.submat, self.subtrans.translated(t)) }
}

impl<M: Rotation<AV> + RMul<V> + One,
     V,
     AV>
Rotation<AV> for Transform<M, V>
{
  #[inline]
  fn rotation(&self) -> AV
  { self.submat.rotation() }

  #[inline]
  fn inv_rotation(&self) -> AV
  { self.submat.inv_rotation() }

  #[inline]
  fn rotate_by(&mut self, rot: &AV)
  {
    // FIXME: this does not seem opitmal
    let mut delta = One::one::<M>();
    delta.rotate_by(rot);
    self.submat.rotate_by(rot);
    self.subtrans = delta.rmul(&self.subtrans);
  }
}

impl<M: Rotate<V>, V, _0> Rotate<V> for Transform<M, _0>
{
  #[inline]
  fn rotate(&self, v: &V) -> V
  { self.submat.rotate(v) }

  #[inline]
  fn inv_rotate(&self, v: &V) -> V
  { self.submat.inv_rotate(v) }
}

impl<M: Rotatable<AV, Res> + One,
     Res: Rotation<AV> + RMul<V> + One,
     V,
     AV>
Rotatable<AV, Transform<Res, V>> for Transform<M, V>
{
  #[inline]
  fn rotated(&self, rot: &AV) -> Transform<Res, V>
  {
    // FIXME: this does not seem opitmal
    let delta = One::one::<M>().rotated(rot);

    Transform::new(self.submat.rotated(rot), delta.rmul(&self.subtrans))
  }
}

impl<M: Inv + RMul<V> + Mul<M, M> + Copy, V: Add<V, V> + Neg<V> + Copy>
Transformation<Transform<M, V>> for Transform<M, V>
{
  fn transformation(&self) -> Transform<M, V>
  { copy *self }

  fn inv_transformation(&self) -> Transform<M, V>
  { self.inverse() }

  fn transform_by(&mut self, other: &Transform<M, V>)
  { *self = other * *self; }
}

impl<M: transformation::Transform<V>, V: Add<V, V> + Sub<V, V>>
transformation::Transform<V> for Transform<M, V>
{
  #[inline]
  fn transform_vec(&self, v: &V) -> V
  { self.submat.transform_vec(v) + self.subtrans }

  #[inline]
  fn inv_transform(&self, v: &V) -> V
  { self.submat.inv_transform(&(v - self.subtrans)) }
}

// FIXME: constraints are too restrictive.
// Should be: Transformable<M2, // Transform<Res, V> ...
impl<M: RMul<V> + Mul<M, M> + Inv, V: Add<V, V> + Neg<V>>
Transformable<Transform<M, V>, Transform<M, V>> for Transform<M, V>
{
  fn transformed(&self, t: &Transform<M, V>) -> Transform<M, V>
  { t * *self }
}

impl<M: Copy + Inv + RMul<V>, V: Copy + Neg<V>>
Inv for Transform<M, V>
{
  #[inline]
  fn invert(&mut self)
  {
    self.submat.invert();
    self.subtrans = self.submat.rmul(&-self.subtrans);
  }

  #[inline]
  fn inverse(&self) -> Transform<M, V>
  {
    let mut res = copy *self;

    res.invert();

    res
  }
}

impl<M: ToHomogeneous<M2>, M2: Dim + Column<V>, V: Copy>
ToHomogeneous<M2> for Transform<M, V>
{
  fn to_homogeneous(&self) -> M2
  {
    let mut res = self.submat.to_homogeneous();

    // copy the translation
    let dim = Dim::dim::<M2>();

    res.set_column(dim - 1, copy self.subtrans);

    res
  }
}

impl<M: Column<V> + Dim, M2: FromHomogeneous<M>, V: Copy>
FromHomogeneous<M> for Transform<M2, V>
{
  fn from_homogeneous(m: &M) -> Transform<M2, V>
  {
    Transform::new(FromHomogeneous::from_homogeneous(m),
                   m.column(Dim::dim::<M>() - 1))
  }
}

impl<N: ApproxEq<N>, M:ApproxEq<N>, V:ApproxEq<N>>
ApproxEq<N> for Transform<M, V>
{
  #[inline]
  fn approx_epsilon() -> N
  { ApproxEq::approx_epsilon::<N, N>() }

  #[inline]
  fn approx_eq(&self, other: &Transform<M, V>) -> bool
  {
    self.submat.approx_eq(&other.submat) &&
    self.subtrans.approx_eq(&other.subtrans)
  }

  #[inline]
  fn approx_eq_eps(&self, other: &Transform<M, V>, epsilon: &N) -> bool
  {
    self.submat.approx_eq_eps(&other.submat, epsilon) &&
    self.subtrans.approx_eq_eps(&other.subtrans, epsilon)
  }
}

impl<M: Rand, V: Rand> Rand for Transform<M, V>
{
  #[inline]
  fn rand<R: Rng>(rng: &mut R) -> Transform<M, V>
  { Transform::new(rng.gen(), rng.gen()) }
}
<|endoftext|>


<commit_before><commit_msg>svlog: ast: Make Expr a node<commit_after><|endoftext|>