<commit_before>//! External names.
//!
//! These are identifiers for declaring entities defined outside the current
//! function. The name of an external declaration doesn't have any meaning to
//! Cretonne, which compiles functions independently.

use std::fmt::{self, Write};

const TESTCASE_NAME_LENGTH: usize = 10;

/// The name of an external is either a reference to a user-defined symbol
/// table, or a short sequence of ascii bytes so that test cases do not have
/// to keep track of a sy mbol table.
///
/// External names are primarily used as keys by code using Cretonne to map
/// from a cretonne::ir::FuncRef or similar to additional associated data.
///
/// External names can also serve as a primitive testing and debugging tool.
/// In particular, many `.cton` test files use function names to identify
/// functions.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExternalName {
    /// A name in a user-defined symbol table. Cretonne does not interpret
    /// these numbers in any way.
    User {
        /// Arbitrary
        namespace: u32,
        /// Arbitrary
        index: u32,
    },
    /// A test case function name of up to 10 ascii characters. This is
    /// not intended to be used outside test cases.
    TestCase {
        /// How many of the bytes in `ascii` are valid
        length: u8,
        /// Ascii bytes of the name
        ascii: [u8; TESTCASE_NAME_LENGTH],
    },
}

impl ExternalName {
    /// Creates a new external name from a sequence of bytes. Caller is expected
    /// to guarantee bytes are only ascii alphanumeric or `_`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cretonne::ir::ExternalName;
    /// // Create `ExternalName` from a string.
    /// let name = ExternalName::testcase("hello");
    /// assert_eq!(name.to_string(), "%hello");
    /// ```
    pub fn testcase<T>(v: T) -> ExternalName
    where
        T: Into<Vec<u8>>,
    {
        let vec = v.into();
        let len = if vec.len() > TESTCASE_NAME_LENGTH {
            TESTCASE_NAME_LENGTH
        } else {
            vec.len()
        };
        let mut bytes = [0u8; TESTCASE_NAME_LENGTH];
        for (i, &byte) in vec.iter().take(len).enumerate() {
            bytes[i] = byte;
        }
        ExternalName::TestCase {
            length: len as u8,
            ascii: bytes,
        }
    }

    /// Create a new external name from user-provided integer indicies.
    ///
    /// # Examples
    /// ```rust
    /// # use cretonne::ir::ExternalName;
    /// // Create `ExternalName` from integer indicies
    /// let name = ExternalName::user(123, 456);
    /// assert_eq!(name.to_string(), "u123:456");
    /// ```
    pub fn user(namespace: u32, index: u32) -> ExternalName {
        ExternalName::User {
            namespace: namespace,
            index: index,
        }
    }
}

impl Default for ExternalName {
    fn default() -> ExternalName {
        ExternalName::user(0, 0)
    }
}

impl fmt::Display for ExternalName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ExternalName::User { namespace, index } => write!(f, "u{}:{}", namespace, index),
            ExternalName::TestCase { length, ascii } => {
                f.write_char('%')?;
                for byte in ascii.iter().take(length as usize) {
                    f.write_char(*byte as char)?;
                }
                Ok(())
            }
        }
    }
}

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

    #[test]
    fn display_testcase() {
        assert_eq!(ExternalName::testcase("").to_string(), "%");
        assert_eq!(ExternalName::testcase("x").to_string(), "%x");
        assert_eq!(ExternalName::testcase("x_1").to_string(), "%x_1");
        assert_eq!(
            ExternalName::testcase("long123456").to_string(),
            "%long123456"
        );
        // Constructor will silently drop bytes beyond the 10th
        assert_eq!(
            ExternalName::testcase("long1234567").to_string(),
            "%long123456"
        );
    }

    #[test]
    fn display_user() {
        assert_eq!(ExternalName::user(0, 0).to_string(), "u0:0");
        assert_eq!(ExternalName::user(1, 1).to_string(), "u1:1");
        assert_eq!(
            ExternalName::user(::std::u32::MAX, ::std::u32::MAX).to_string(),
            "u4294967295:4294967295"
        );
    }
}
<commit_msg>extname: extend testcases to 16 chars<commit_after>//! External names.
//!
//! These are identifiers for declaring entities defined outside the current
//! function. The name of an external declaration doesn't have any meaning to
//! Cretonne, which compiles functions independently.

use std::fmt::{self, Write};

const TESTCASE_NAME_LENGTH: usize = 16;

/// The name of an external is either a reference to a user-defined symbol
/// table, or a short sequence of ascii bytes so that test cases do not have
/// to keep track of a sy mbol table.
///
/// External names are primarily used as keys by code using Cretonne to map
/// from a cretonne::ir::FuncRef or similar to additional associated data.
///
/// External names can also serve as a primitive testing and debugging tool.
/// In particular, many `.cton` test files use function names to identify
/// functions.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExternalName {
    /// A name in a user-defined symbol table. Cretonne does not interpret
    /// these numbers in any way.
    User {
        /// Arbitrary
        namespace: u32,
        /// Arbitrary
        index: u32,
    },
    /// A test case function name of up to 10 ascii characters. This is
    /// not intended to be used outside test cases.
    TestCase {
        /// How many of the bytes in `ascii` are valid
        length: u8,
        /// Ascii bytes of the name
        ascii: [u8; TESTCASE_NAME_LENGTH],
    },
}

impl ExternalName {
    /// Creates a new external name from a sequence of bytes. Caller is expected
    /// to guarantee bytes are only ascii alphanumeric or `_`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cretonne::ir::ExternalName;
    /// // Create `ExternalName` from a string.
    /// let name = ExternalName::testcase("hello");
    /// assert_eq!(name.to_string(), "%hello");
    /// ```
    pub fn testcase<T>(v: T) -> ExternalName
    where
        T: Into<Vec<u8>>,
    {
        let vec = v.into();
        let len = if vec.len() > TESTCASE_NAME_LENGTH {
            TESTCASE_NAME_LENGTH
        } else {
            vec.len()
        };
        let mut bytes = [0u8; TESTCASE_NAME_LENGTH];
        for (i, &byte) in vec.iter().take(len).enumerate() {
            bytes[i] = byte;
        }
        ExternalName::TestCase {
            length: len as u8,
            ascii: bytes,
        }
    }

    /// Create a new external name from user-provided integer indicies.
    ///
    /// # Examples
    /// ```rust
    /// # use cretonne::ir::ExternalName;
    /// // Create `ExternalName` from integer indicies
    /// let name = ExternalName::user(123, 456);
    /// assert_eq!(name.to_string(), "u123:456");
    /// ```
    pub fn user(namespace: u32, index: u32) -> ExternalName {
        ExternalName::User {
            namespace: namespace,
            index: index,
        }
    }
}

impl Default for ExternalName {
    fn default() -> ExternalName {
        ExternalName::user(0, 0)
    }
}

impl fmt::Display for ExternalName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ExternalName::User { namespace, index } => write!(f, "u{}:{}", namespace, index),
            ExternalName::TestCase { length, ascii } => {
                f.write_char('%')?;
                for byte in ascii.iter().take(length as usize) {
                    f.write_char(*byte as char)?;
                }
                Ok(())
            }
        }
    }
}

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

    #[test]
    fn display_testcase() {
        assert_eq!(ExternalName::testcase("").to_string(), "%");
        assert_eq!(ExternalName::testcase("x").to_string(), "%x");
        assert_eq!(ExternalName::testcase("x_1").to_string(), "%x_1");
        assert_eq!(
            ExternalName::testcase("longname12345678").to_string(),
            "%longname12345678"
        );
        // Constructor will silently drop bytes beyond the 16th
        assert_eq!(
            ExternalName::testcase("longname123456789").to_string(),
            "%longname12345678"
        );
    }

    #[test]
    fn display_user() {
        assert_eq!(ExternalName::user(0, 0).to_string(), "u0:0");
        assert_eq!(ExternalName::user(1, 1).to_string(), "u1:1");
        assert_eq!(
            ExternalName::user(::std::u32::MAX, ::std::u32::MAX).to_string(),
            "u4294967295:4294967295"
        );
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::collections::HashSet;
use std::fmt;
use std::fmt::Write as _;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::path::MAIN_SEPARATOR;
use std::str;
use tempfile::NamedTempFile;

use protobuf::descriptor::{
    DescriptorProto, EnumDescriptorProto, FileDescriptorProto, FileDescriptorSet,
};
use protobuf::RepeatedField;
use protobuf_test_common::build::copy_tests_v2_v3;
use protobuf_test_common::build::glob_simple;
use std::process::Command;
use std::process::Stdio;

fn to_paths(iter: impl IntoIterator<Item = impl Into<String>>) -> Vec<PathBuf> {
    iter.into_iter()
        .map(|item| item.into().replace(MAIN_SEPARATOR, "/").into())
        .collect()
}

#[derive(Default, Debug)]
struct TestStats {
    passed: u32,
    passed_marked_skip: u32,
    skipped: u32,
    failed: u32,
}

fn normalize_generated_file(contents: &str) -> String {
    let parsed_by = Regex::new("^// \\.proto file is parsed by.*").unwrap();

    let mut r = String::new();
    let mut inside_descriptor_data = false;
    for line in contents.lines() {
        let line = if inside_descriptor_data {
            if line == "\";" {
                inside_descriptor_data = false;
                line.to_owned()
            } else {
                continue;
            }
        } else if line.starts_with("static file_descriptor_proto_data") {
            inside_descriptor_data = true;
            line.to_owned()
        } else {
            parsed_by.replace(line, "").into_owned()
        };

        writeln!(&mut r, "{}", line).unwrap();
    }

    // sanity check
    assert!(!inside_descriptor_data);

    r
}

fn normalize_generated_file_in_place(path: &Path) {
    let contents = fs::read_to_string(path).unwrap();
    let contents = normalize_generated_file(&contents);
    fs::write(path, &contents).unwrap();
}

fn print_diff(dir: &Path, a: &Path, b: &Path) {
    if cfg!(windows) {
        // likely we don't have `diff` command on Windows
        return;
    }

    // sanity check
    let mut a_full = dir.to_path_buf();
    a_full.push(a);
    assert!(a_full.exists());
    let mut b_full = dir.to_path_buf();
    b_full.push(b);
    assert!(b_full.exists());

    // Not using difference crate because it's slow for large files
    let output = Command::new("diff")
        .current_dir(dir)
        .arg("-u")
        .arg(a)
        .arg(b)
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .output()
        .unwrap();

    print!("{}", str::from_utf8(&output.stdout).unwrap());
    print!("{}", str::from_utf8(&output.stderr).unwrap());
}

fn protoc_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut temp_file = NamedTempFile::new().unwrap();
    protoc::Protoc::from_env_path()
        .descriptor_set_out_args()
        .out(temp_file.path())
        .includes(includes)
        .inputs(inputs)
        .write_descriptor_set()
        .unwrap();
    protobuf::parse_from_reader(&mut temp_file).unwrap()
}

// TODO: expose this utility from protobuf-codegen-pure crate.
fn pure_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut codegen = protobuf_codegen_pure::parse_and_typecheck(includes, inputs).unwrap();
    let relative_paths: HashSet<_> = codegen
        .relative_paths
        .iter()
        .map(|path| path.to_string_lossy())
        .collect();
    codegen
        .file_descriptors
        .retain(|fd| relative_paths.contains(fd.get_name()));
    let mut fds = FileDescriptorSet::new();
    fds.file = RepeatedField::from_vec(codegen.file_descriptors);
    fds
}

fn normalize_descriptor_set(fds: &mut FileDescriptorSet) {
    for desc in fds.file.iter_mut() {
        normalize_file_descriptor(desc)
    }
}

fn normalize_file_descriptor(desc: &mut FileDescriptorProto) {
    if !desc.has_syntax() {
        desc.set_syntax("proto2".into())
    }
    for desc in &mut *desc.message_type {
        normalize_descriptor(desc)
    }
    for desc in desc.enum_type.iter_mut() {
        normalize_enum_descriptor(desc)
    }

    // TODO: don't clear options.
    for desc in &mut *desc.extension {
        desc.options.clear();
    }
    desc.options.clear();

    // TODO: don't clear services.
    desc.service.clear();
}

fn normalize_enum_descriptor(desc: &mut EnumDescriptorProto) {
    desc.options.mut_or_default();

    for value in desc.value.iter_mut() {
        value.options.mut_or_default();
    }
}

fn normalize_descriptor(desc: &mut DescriptorProto) {
    for desc in desc.nested_type.iter_mut() {
        normalize_descriptor(desc);
    }
    for desc in desc.enum_type.iter_mut() {
        normalize_enum_descriptor(desc);
    }

    // TODO: don't clear options.
    desc.options.clear();
    for field in desc.field.iter_mut() {
        field.options.clear();
    }
}

fn pretty_message<M: protobuf::Message>(message: &M) -> String {
    // TODO: pull this handy utility into the protobuf crate.
    struct FormatMessage<'a, M>(&'a M);

    impl<M: protobuf::Message> fmt::Display for FormatMessage<'_, M> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            protobuf::text_format::fmt(self.0, f)
        }
    }

    format!("{:#}", FormatMessage(message))
}

fn test_diff_in<F>(root: &str, s: &str, include: &str, should_skip: F)
where
    F: Fn(&str) -> bool,
{
    let mut stats = TestStats {
        passed: 0,
        passed_marked_skip: 0,
        skipped: 0,
        failed: 0,
    };

    let include_full = format!("{}/{}", root, include);
    let s_full = format!("{}/{}", root, s);

    let inputs_glob = format!("{}/*.proto", s_full);
    let inputs = to_paths(glob_simple(&inputs_glob));
    assert!(!inputs.is_empty(), "glob is empty: {}", inputs_glob);
    let includes = to_paths(vec![include_full.as_str(), "../proto"]);

    let temp_dir = tempfile::Builder::new()
        .prefix("protobuf-codegen-identical-test")
        .tempdir()
        .unwrap();

    let protoc_dir = format!("{}/protoc", temp_dir.path().to_str().unwrap());
    let pure_dir = format!("{}/pure", temp_dir.path().to_str().unwrap());

    fs::create_dir(&protoc_dir).unwrap();
    fs::create_dir(&pure_dir).unwrap();

    protoc_rust::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&protoc_dir)
        .run()
        .unwrap();

    protobuf_codegen_pure::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&pure_dir)
        .run()
        .unwrap();

    for input in &inputs {
        let label = input.strip_prefix(root).unwrap().to_str().unwrap();
        let proto_name = input.file_name().unwrap().to_str().unwrap();
        let rs_name = protobuf_codegen::proto_name_to_rs(proto_name);
        let protoc_rs = format!("{}/{}", protoc_dir, rs_name);
        let pure_rs = format!("{}/{}", pure_dir, rs_name);

        normalize_generated_file_in_place(Path::new(&protoc_rs));
        normalize_generated_file_in_place(Path::new(&pure_rs));

        let protoc_rs_contents =
            fs::read_to_string(&protoc_rs).expect(&format!("while reading {}", protoc_rs));
        let pure_rs_contents =
            fs::read_to_string(&pure_rs).expect(&format!("while reading {}", pure_rs));

        let mut protoc_descriptors = protoc_descriptor_set(&includes, &inputs);
        let mut pure_descriptors = pure_descriptor_set(&includes, &inputs);
        normalize_descriptor_set(&mut protoc_descriptors);
        normalize_descriptor_set(&mut pure_descriptors);

        let skip = should_skip(input.to_str().unwrap());
        if protoc_rs_contents == pure_rs_contents && protoc_descriptors == pure_descriptors {
            if !skip {
                stats.passed += 1;
                println!("{}: PASSED", label);
            } else {
                stats.passed_marked_skip += 1;
                println!("{}: PASSED BUT MARKED SKIP", label);
            }
        } else {
            if skip {
                stats.skipped += 1;
                println!("{} SKIPPED", label);
            } else {
                stats.failed += 1;
                println!("{} FAILED", label);
            }

            print_diff(
                temp_dir.path(),
                Path::new(&protoc_rs).strip_prefix(temp_dir.path()).unwrap(),
                Path::new(&pure_rs).strip_prefix(temp_dir.path()).unwrap(),
            );

            fs::write(
                format!("{}/{}.descriptors", protoc_dir, proto_name),
                pretty_message(&protoc_descriptors),
            )
            .unwrap();
            fs::write(
                format!("{}/{}.descriptors", pure_dir, proto_name),
                pretty_message(&pure_descriptors),
            )
            .unwrap();
            print_diff(
                temp_dir.path(),
                Path::new(&format!("protoc/{}.descriptors", proto_name)),
                Path::new(&format!("pure/{}.descriptors", proto_name)),
            );
        }
    }

    println!("{:?}", stats);
    assert!(
        stats.passed != 0 || s == "src/google/protobuf",
        "sanity check"
    );
    assert!(stats.failed == 0, "at least one test failed");
}

fn should_skip_with_marker(path: &str) -> bool {
    fs::read_to_string(path)
        .unwrap()
        .contains("@skip-codegen-identical-test")
}

#[test]
fn common_v2() {
    test_diff_in(
        "../protobuf-test",
        "src/common/v2",
        "src/common/v2",
        should_skip_with_marker,
    );
}

#[test]
fn common_v3() {
    let common_v3_root = tempfile::Builder::new()
        .prefix("common-v3")
        .tempdir()
        .unwrap();
    fs::create_dir_all(format!(
        "{}/src/common/v3",
        common_v3_root.path().to_str().unwrap()
    ))
    .unwrap();

    copy_tests_v2_v3(
        "../protobuf-test/src/common/v2",
        &format!("{}/src/common/v3", common_v3_root.path().to_str().unwrap()),
    );

    test_diff_in(
        common_v3_root.path().to_str().unwrap(),
        "src/common/v3",
        "src/common/v3",
        should_skip_with_marker,
    );
}

#[test]
fn v2() {
    test_diff_in(
        "../protobuf-test",
        "src/v2",
        "src/v2",
        should_skip_with_marker,
    );
}

#[test]
fn v3() {
    test_diff_in(
        "../protobuf-test",
        "src/v3",
        "src/v3",
        should_skip_with_marker,
    );
}

#[test]
fn interop() {
    test_diff_in(
        "../protobuf-test",
        "../interop/cxx",
        "../interop/cxx",
        should_skip_with_marker,
    );
}

#[test]
fn google() {
    test_diff_in("../protobuf-test", "src/google/protobuf", "src", |_| true);
}
<commit_msg>Do not clear field options when performing ident tests<commit_after>use regex::Regex;
use std::collections::HashSet;
use std::fmt;
use std::fmt::Write as _;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::path::MAIN_SEPARATOR;
use std::str;
use tempfile::NamedTempFile;

use protobuf::descriptor::{
    DescriptorProto, EnumDescriptorProto, FileDescriptorProto, FileDescriptorSet,
};
use protobuf::RepeatedField;
use protobuf_test_common::build::copy_tests_v2_v3;
use protobuf_test_common::build::glob_simple;
use std::process::Command;
use std::process::Stdio;

fn to_paths(iter: impl IntoIterator<Item = impl Into<String>>) -> Vec<PathBuf> {
    iter.into_iter()
        .map(|item| item.into().replace(MAIN_SEPARATOR, "/").into())
        .collect()
}

#[derive(Default, Debug)]
struct TestStats {
    passed: u32,
    passed_marked_skip: u32,
    skipped: u32,
    failed: u32,
}

fn normalize_generated_file(contents: &str) -> String {
    let parsed_by = Regex::new("^// \\.proto file is parsed by.*").unwrap();

    let mut r = String::new();
    let mut inside_descriptor_data = false;
    for line in contents.lines() {
        let line = if inside_descriptor_data {
            if line == "\";" {
                inside_descriptor_data = false;
                line.to_owned()
            } else {
                continue;
            }
        } else if line.starts_with("static file_descriptor_proto_data") {
            inside_descriptor_data = true;
            line.to_owned()
        } else {
            parsed_by.replace(line, "").into_owned()
        };

        writeln!(&mut r, "{}", line).unwrap();
    }

    // sanity check
    assert!(!inside_descriptor_data);

    r
}

fn normalize_generated_file_in_place(path: &Path) {
    let contents = fs::read_to_string(path).unwrap();
    let contents = normalize_generated_file(&contents);
    fs::write(path, &contents).unwrap();
}

fn print_diff(dir: &Path, a: &Path, b: &Path) {
    if cfg!(windows) {
        // likely we don't have `diff` command on Windows
        return;
    }

    // sanity check
    let mut a_full = dir.to_path_buf();
    a_full.push(a);
    assert!(a_full.exists());
    let mut b_full = dir.to_path_buf();
    b_full.push(b);
    assert!(b_full.exists());

    // Not using difference crate because it's slow for large files
    let output = Command::new("diff")
        .current_dir(dir)
        .arg("-u")
        .arg(a)
        .arg(b)
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .output()
        .unwrap();

    print!("{}", str::from_utf8(&output.stdout).unwrap());
    print!("{}", str::from_utf8(&output.stderr).unwrap());
}

fn protoc_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut temp_file = NamedTempFile::new().unwrap();
    protoc::Protoc::from_env_path()
        .descriptor_set_out_args()
        .out(temp_file.path())
        .includes(includes)
        .inputs(inputs)
        .write_descriptor_set()
        .unwrap();
    protobuf::parse_from_reader(&mut temp_file).unwrap()
}

// TODO: expose this utility from protobuf-codegen-pure crate.
fn pure_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut codegen = protobuf_codegen_pure::parse_and_typecheck(includes, inputs).unwrap();
    let relative_paths: HashSet<_> = codegen
        .relative_paths
        .iter()
        .map(|path| path.to_string_lossy())
        .collect();
    codegen
        .file_descriptors
        .retain(|fd| relative_paths.contains(fd.get_name()));
    let mut fds = FileDescriptorSet::new();
    fds.file = RepeatedField::from_vec(codegen.file_descriptors);
    fds
}

fn normalize_descriptor_set(fds: &mut FileDescriptorSet) {
    for desc in fds.file.iter_mut() {
        normalize_file_descriptor(desc)
    }
}

fn normalize_file_descriptor(desc: &mut FileDescriptorProto) {
    if !desc.has_syntax() {
        desc.set_syntax("proto2".into())
    }
    for desc in &mut *desc.message_type {
        normalize_descriptor(desc)
    }
    for desc in desc.enum_type.iter_mut() {
        normalize_enum_descriptor(desc)
    }

    // TODO: don't clear options.
    for desc in &mut *desc.extension {
        desc.options.clear();
    }
    desc.options.clear();

    // TODO: don't clear services.
    desc.service.clear();
}

fn normalize_enum_descriptor(desc: &mut EnumDescriptorProto) {
    desc.options.mut_or_default();

    for value in desc.value.iter_mut() {
        value.options.mut_or_default();
    }
}

fn normalize_descriptor(desc: &mut DescriptorProto) {
    for desc in desc.nested_type.iter_mut() {
        normalize_descriptor(desc);
    }
    for desc in desc.enum_type.iter_mut() {
        normalize_enum_descriptor(desc);
    }

    // TODO: don't clear options.
    desc.options.clear();
    for field in desc.field.iter_mut() {
        field.options.mut_or_default();
    }
}

fn pretty_message<M: protobuf::Message>(message: &M) -> String {
    // TODO: pull this handy utility into the protobuf crate.
    struct FormatMessage<'a, M>(&'a M);

    impl<M: protobuf::Message> fmt::Display for FormatMessage<'_, M> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            protobuf::text_format::fmt(self.0, f)
        }
    }

    format!("{:#}", FormatMessage(message))
}

fn test_diff_in<F>(root: &str, s: &str, include: &str, should_skip: F)
where
    F: Fn(&str) -> bool,
{
    let mut stats = TestStats {
        passed: 0,
        passed_marked_skip: 0,
        skipped: 0,
        failed: 0,
    };

    let include_full = format!("{}/{}", root, include);
    let s_full = format!("{}/{}", root, s);

    let inputs_glob = format!("{}/*.proto", s_full);
    let inputs = to_paths(glob_simple(&inputs_glob));
    assert!(!inputs.is_empty(), "glob is empty: {}", inputs_glob);
    let includes = to_paths(vec![include_full.as_str(), "../proto"]);

    let temp_dir = tempfile::Builder::new()
        .prefix("protobuf-codegen-identical-test")
        .tempdir()
        .unwrap();

    let protoc_dir = format!("{}/protoc", temp_dir.path().to_str().unwrap());
    let pure_dir = format!("{}/pure", temp_dir.path().to_str().unwrap());

    fs::create_dir(&protoc_dir).unwrap();
    fs::create_dir(&pure_dir).unwrap();

    protoc_rust::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&protoc_dir)
        .run()
        .unwrap();

    protobuf_codegen_pure::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&pure_dir)
        .run()
        .unwrap();

    for input in &inputs {
        let label = input.strip_prefix(root).unwrap().to_str().unwrap();
        let proto_name = input.file_name().unwrap().to_str().unwrap();
        let rs_name = protobuf_codegen::proto_name_to_rs(proto_name);
        let protoc_rs = format!("{}/{}", protoc_dir, rs_name);
        let pure_rs = format!("{}/{}", pure_dir, rs_name);

        normalize_generated_file_in_place(Path::new(&protoc_rs));
        normalize_generated_file_in_place(Path::new(&pure_rs));

        let protoc_rs_contents =
            fs::read_to_string(&protoc_rs).expect(&format!("while reading {}", protoc_rs));
        let pure_rs_contents =
            fs::read_to_string(&pure_rs).expect(&format!("while reading {}", pure_rs));

        let mut protoc_descriptors = protoc_descriptor_set(&includes, &inputs);
        let mut pure_descriptors = pure_descriptor_set(&includes, &inputs);
        normalize_descriptor_set(&mut protoc_descriptors);
        normalize_descriptor_set(&mut pure_descriptors);

        let skip = should_skip(input.to_str().unwrap());
        if protoc_rs_contents == pure_rs_contents && protoc_descriptors == pure_descriptors {
            if !skip {
                stats.passed += 1;
                println!("{}: PASSED", label);
            } else {
                stats.passed_marked_skip += 1;
                println!("{}: PASSED BUT MARKED SKIP", label);
            }
        } else {
            if skip {
                stats.skipped += 1;
                println!("{} SKIPPED", label);
            } else {
                stats.failed += 1;
                println!("{} FAILED", label);
            }

            print_diff(
                temp_dir.path(),
                Path::new(&protoc_rs).strip_prefix(temp_dir.path()).unwrap(),
                Path::new(&pure_rs).strip_prefix(temp_dir.path()).unwrap(),
            );

            fs::write(
                format!("{}/{}.descriptors", protoc_dir, proto_name),
                pretty_message(&protoc_descriptors),
            )
            .unwrap();
            fs::write(
                format!("{}/{}.descriptors", pure_dir, proto_name),
                pretty_message(&pure_descriptors),
            )
            .unwrap();
            print_diff(
                temp_dir.path(),
                Path::new(&format!("protoc/{}.descriptors", proto_name)),
                Path::new(&format!("pure/{}.descriptors", proto_name)),
            );
        }
    }

    println!("{:?}", stats);
    assert!(
        stats.passed != 0 || s == "src/google/protobuf",
        "sanity check"
    );
    assert!(stats.failed == 0, "at least one test failed");
}

fn should_skip_with_marker(path: &str) -> bool {
    fs::read_to_string(path)
        .unwrap()
        .contains("@skip-codegen-identical-test")
}

#[test]
fn common_v2() {
    test_diff_in(
        "../protobuf-test",
        "src/common/v2",
        "src/common/v2",
        should_skip_with_marker,
    );
}

#[test]
fn common_v3() {
    let common_v3_root = tempfile::Builder::new()
        .prefix("common-v3")
        .tempdir()
        .unwrap();
    fs::create_dir_all(format!(
        "{}/src/common/v3",
        common_v3_root.path().to_str().unwrap()
    ))
    .unwrap();

    copy_tests_v2_v3(
        "../protobuf-test/src/common/v2",
        &format!("{}/src/common/v3", common_v3_root.path().to_str().unwrap()),
    );

    test_diff_in(
        common_v3_root.path().to_str().unwrap(),
        "src/common/v3",
        "src/common/v3",
        should_skip_with_marker,
    );
}

#[test]
fn v2() {
    test_diff_in(
        "../protobuf-test",
        "src/v2",
        "src/v2",
        should_skip_with_marker,
    );
}

#[test]
fn v3() {
    test_diff_in(
        "../protobuf-test",
        "src/v3",
        "src/v3",
        should_skip_with_marker,
    );
}

#[test]
fn interop() {
    test_diff_in(
        "../protobuf-test",
        "../interop/cxx",
        "../interop/cxx",
        should_skip_with_marker,
    );
}

#[test]
fn google() {
    test_diff_in("../protobuf-test", "src/google/protobuf", "src", |_| true);
}
<|endoftext|>


<commit_before>//! Generic serialization framework.

#[cfg(feature = "std")]
use std::error;
#[cfg(not(feature = "std"))]
use error;

#[cfg(all(feature = "collections", not(feature = "std")))]
use collections::String;

pub mod impls;

///////////////////////////////////////////////////////////////////////////////

/// `Error` is a trait that allows a `Serialize` to generically create a
/// `Serializer` error.
pub trait Error: Sized + error::Error {
    /// Raised when there is general error when deserializing a type.
    #[cfg(any(feature = "std", feature = "collections"))]
    fn custom<T: Into<String>>(msg: T) -> Self;

    /// Raised when there is general error when deserializing a type.
    #[cfg(all(not(feature = "std"), not(feature = "collections")))]
    fn custom<T: Into<&'static str>>(msg: T) -> Self;

    /// Raised when a `Serialize` was passed an incorrect value.
    fn invalid_value(msg: &str) -> Self {
        Error::custom(format!("invalid value: {}", msg))
    }
}

///////////////////////////////////////////////////////////////////////////////

/// A trait that describes a type that can be serialized by a `Serializer`.
pub trait Serialize {
    /// Serializes this value into this serializer.
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer;
}

///////////////////////////////////////////////////////////////////////////////

/// A trait that describes a type that can serialize a stream of values into the underlying format.
pub trait Serializer {
    /// The error type that can be returned if some error occurs during serialization.
    type Error: Error;
    /// A state object that is returned from `serialize_seq` and needs to be re-inserted into
    /// `serialize_seq_end` when the serialization of the sequence is done
    type SeqState;
    /// A state object that is returned from `serialize_map` and needs to be re-inserted into
    /// `serialize_map_end` when the serialization of the map is done
    type MapState;

    /// Serializes a `bool` value.
    fn serialize_bool(&mut self, v: bool) -> Result<(), Self::Error>;

    /// Serializes a `isize` value. By default it casts the value to a `i64` and
    /// passes it to the `serialize_i64` method.
    #[inline]
    fn serialize_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        self.serialize_i64(v as i64)
    }

    /// Serializes a `i8` value. By default it casts the value to a `i64` and
    /// passes it to the `serialize_i64` method.
    #[inline]
    fn serialize_i8(&mut self, v: i8) -> Result<(), Self::Error> {
        self.serialize_i64(v as i64)
    }

    /// Serializes a `i16` value. By default it casts the value to a `i64` and
    /// passes it to the `serialize_i64` method.
    #[inline]
    fn serialize_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.serialize_i64(v as i64)
    }

    /// Serializes a `i32` value. By default it casts the value to a `i64` and
    /// passes it to the `serialize_i64` method.
    #[inline]
    fn serialize_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.serialize_i64(v as i64)
    }

    /// Serializes a `i64` value.
    #[inline]
    fn serialize_i64(&mut self, v: i64) -> Result<(), Self::Error>;

    /// Serializes a `usize` value. By default it casts the value to a `u64` and
    /// passes it to the `serialize_u64` method.
    #[inline]
    fn serialize_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        self.serialize_u64(v as u64)
    }

    /// Serializes a `u8` value. By default it casts the value to a `u64` and passes
    /// it to the `serialize_u64` method.
    #[inline]
    fn serialize_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        self.serialize_u64(v as u64)
    }

    /// Serializes a `u32` value. By default it casts the value to a `u64` and passes
    /// it to the `serialize_u64` method.
    #[inline]
    fn serialize_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        self.serialize_u64(v as u64)
    }

    /// Serializes a `u32` value. By default it casts the value to a `u64` and passes
    /// it to the `serialize_u64` method.
    #[inline]
    fn serialize_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        self.serialize_u64(v as u64)
    }

    /// `Serializes a `u64` value.
    #[inline]
    fn serialize_u64(&mut self, v: u64) -> Result<(), Self::Error>;

    /// Serializes a `f32` value. By default it casts the value to a `f64` and passes
    /// it to the `serialize_f64` method.
    #[inline]
    fn serialize_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.serialize_f64(v as f64)
    }

    /// Serializes a `f64` value.
    fn serialize_f64(&mut self, v: f64) -> Result<(), Self::Error>;

    /// Serializes a character. By default it serializes it as a `&str` containing a
    /// single character.
    #[inline]
    fn serialize_char(&mut self, v: char) -> Result<(), Self::Error> {
        self.serialize_str(::utils::encode_utf8(v).as_str())
    }

    /// Serializes a `&str`.
    fn serialize_str(&mut self, value: &str) -> Result<(), Self::Error>;

    /// Enables those serialization formats that support serializing
    /// byte slices separately from generic arrays. By default it serializes as a regular array.
    #[inline]
    fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error> {
        let state = try!(self.serialize_seq(Some(value.len())));
        for b in value.iter() {
            try!(self.serialize_seq_elt(b));
        }
        self.serialize_seq_end(Some(value.len()), state)
    }

    /// Serializes a `()` value.
    fn serialize_unit(&mut self) -> Result<(), Self::Error>;

    /// Serializes a unit struct value.
    ///
    /// By default, unit structs are serialized as a `()`.
    #[inline]
    fn serialize_unit_struct(&mut self, _name: &'static str) -> Result<(), Self::Error> {
        self.serialize_unit()
    }

    /// Serializes a unit variant, otherwise known as a variant with no arguments.
    ///
    /// By default, unit variants are serialized as a `()`.
    #[inline]
    fn serialize_unit_variant(&mut self,
                              _name: &'static str,
                              _variant_index: usize,
                              _variant: &'static str) -> Result<(), Self::Error> {
        self.serialize_unit()
    }

    /// Allows a tuple struct with a single element, also known as a
    /// newtyped value, to be more efficiently serialized than a tuple struct with multiple items.
    /// By default it just serializes the value as a tuple struct sequence.
    #[inline]
    fn serialize_newtype_struct<T>(&mut self,
                                   name: &'static str,
                                   value: T) -> Result<(), Self::Error>
        where T: Serialize,
    {
        let state = try!(self.serialize_tuple_struct(name, 1));
        try!(self.serialize_tuple_struct_elt(value));
        self.serialize_tuple_struct_end(name, 1, state)
    }

    /// Allows a variant with a single item to be more efficiently
    /// serialized than a variant with multiple items. By default it just serializes the value as a
    /// tuple variant sequence.
    #[inline]
    fn serialize_newtype_variant<T>(&mut self,
                                    name: &'static str,
                                    variant_index: usize,
                                    variant: &'static str,
                                    value: T) -> Result<(), Self::Error>
        where T: Serialize,
    {
        let state = try!(self.serialize_tuple_variant(name, variant_index, variant, 1));
        try!(self.serialize_tuple_variant_elt(value));
        self.serialize_tuple_variant_end(name, variant_index, variant, 1, state)
    }

    /// Serializes a `None` value..serialize
    fn serialize_none(&mut self) -> Result<(), Self::Error>;

    /// Serializes a `Some(...)` value.
    fn serialize_some<V>(&mut self, value: V) -> Result<(), Self::Error>
        where V: Serialize;

    /// Serializes a sequence.
    ///
    /// Callees of this method need to construct a `SeqVisitor`, which iterates through each item
    /// in the sequence.
    fn serialize_seq(&mut self, len: Option<usize>) -> Result<Self::SeqState, Self::Error>;

    /// Serializes a sequence element.
    fn serialize_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize;

    /// Finish serializing a sequence.
    fn serialize_seq_end(&mut self, len: Option<usize>, state: Self::SeqState) -> Result<(), Self::Error>;

    /// Serializes a tuple.
    ///
    /// By default this serializes a tuple as a sequence.
    #[inline]
    fn serialize_tuple(&mut self, len: usize) -> Result<Self::SeqState, Self::Error>
    {
        self.serialize_seq(Some(len))
    }

    /// Serializes a tuple element.
    ///
    /// By default, tuples are serialized as a sequence.
    #[inline]
    fn serialize_tuple_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize {
        self.serialize_seq_elt(value)
    }

    /// Finishes serialization of a tuple.
    ///
    /// By default, tuples are serialized as a sequence.
    #[inline]
    fn serialize_tuple_end(&mut self, len: usize, state: Self::SeqState) -> Result<(), Self::Error> {
        self.serialize_seq_end(Some(len), state)
    }

    /// Serializes a fixed-size array.
    ///
    /// By default this serializes an array as a sequence.
    #[inline]
    fn serialize_fixed_size_array(&mut self, size: usize) -> Result<Self::SeqState, Self::Error>
    {
        self.serialize_seq(Some(size))
    }

    /// Serializes a tuple struct.
    ///
    /// By default, tuple structs are serialized as a tuple.
    #[inline]
    fn serialize_tuple_struct(&mut self,
                              _name: &'static str,
                              len: usize,
                             ) -> Result<Self::SeqState, Self::Error>
    {
        self.serialize_tuple(len)
    }

    /// Serializes a tuple struct element.
    ///
    /// By default, tuple struct elements are serialized as a tuple element.
    #[inline]
    fn serialize_tuple_struct_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.serialize_tuple_elt(value)
    }

    /// Finishes serialization of a tuple struct.
    ///
    /// By default, tuple structs are serialized as a sequence.
    #[inline]
    fn serialize_tuple_struct_end(&mut self,
                              _name: &'static str,
                              len: usize,
                              state: Self::SeqState,
                              ) -> Result<(), Self::Error> {
        self.serialize_tuple_end(len, state)
    }

    /// Serializes a tuple variant.
    ///
    /// By default, tuple variants are serialized as a tuple struct.
    #[inline]
    fn serialize_tuple_variant(&mut self,
                               _name: &'static str,
                               _variant_index: usize,
                               variant: &'static str,
                               len: usize,
                               ) -> Result<Self::SeqState, Self::Error>
    {
        self.serialize_tuple_struct(variant, len)
    }

    /// Serializes a tuple variant element.
    ///
    /// By default, tuple variants are serialized as tuples.
    #[inline]
    fn serialize_tuple_variant_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.serialize_tuple_struct_elt(value)
    }

    /// Finishes serialization of a tuple variant.
    ///
    /// By default, tuple variants are serialized as tuples.
    #[inline]
    fn serialize_tuple_variant_end(&mut self,
                               _name: &'static str,
                               _variant_index: usize,
                               variant: &'static str,
                               len: usize,
                               state: Self::SeqState,
                               ) -> Result<(), Self::Error> {
        self.serialize_tuple_struct_end(variant, len, state)
    }

    /// Serialize a map.
    fn serialize_map(&mut self, len: Option<usize>) -> Result<Self::MapState, Self::Error>;

    /// Serialize a map element
    fn serialize_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error> where K: Serialize, V: Serialize;

    /// Finishes serializing a map
    fn serialize_map_end(&mut self, len: Option<usize>, state: Self::MapState) -> Result<(), Self::Error>;

    /// Serializes a struct.
    ///
    /// By default, structs are serialized as a map with the field name as the key.
    #[inline]
    fn serialize_struct(&mut self,
                        _name: &'static str,
                        len: usize,
                        ) -> Result<Self::MapState, Self::Error>
    {
        self.serialize_map(Some(len))
    }

    /// Serialize a struct field
    ///
    /// By default, structs are serialized as a map with the field name as the key.
    fn serialize_struct_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error> where K: Serialize, V: Serialize {
        self.serialize_map_elt(key, value)
    }

    /// Finishes serializing a struct
    ///
    /// By default, structs are serialized as a map with the field name as the key.
    fn serialize_struct_end(&mut self,
                        _name: &'static str,
                        len: usize,
                        state: Self::MapState,
                        ) -> Result<(), Self::Error> {
        self.serialize_map_end(Some(len), state)
    }

    /// Serializes a struct variant.
    ///
    /// By default, struct variants are serialized as a struct.
    #[inline]
    fn serialize_struct_variant(&mut self,
                                   _name: &'static str,
                                   _variant_index: usize,
                                   variant: &'static str,
                                   len: usize,
                               ) -> Result<Self::MapState, Self::Error>
    {
        self.serialize_struct(variant, len)
    }

    /// Serialize a struct variant element
    ///
    /// By default, structs are serialized as a map with the field name as the key.
    fn serialize_struct_variant_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error> where K: Serialize, V: Serialize {
        self.serialize_struct_elt(key, value)
    }

    /// Finishes serializing a struct variant
    ///
    /// By default, structs are serialized as a map with the field name as the key.
    fn serialize_struct_variant_end(&mut self,
                                   _name: &'static str,
                                   _variant_index: usize,
                                   variant: &'static str,
                                   len: usize,
                                   state: Self::MapState,
                               ) -> Result<(), Self::Error> {
        self.serialize_struct_end(variant, len, state)
    }
}
<commit_msg>David's take on Serializer<commit_after>//! Generic serialization framework.

#[cfg(feature = "std")]
use std::error;
#[cfg(not(feature = "std"))]
use error;

#[cfg(all(feature = "collections", not(feature = "std")))]
use collections::String;

pub mod impls;

///////////////////////////////////////////////////////////////////////////////

/// `Error` is a trait that allows a `Serialize` to generically create a
/// `Serializer` error.
pub trait Error: Sized + error::Error {
    /// Raised when there is general error when deserializing a type.
    #[cfg(any(feature = "std", feature = "collections"))]
    fn custom<T: Into<String>>(msg: T) -> Self;

    /// Raised when there is general error when deserializing a type.
    #[cfg(all(not(feature = "std"), not(feature = "collections")))]
    fn custom<T: Into<&'static str>>(msg: T) -> Self;

    /// Raised when a `Serialize` was passed an incorrect value.
    fn invalid_value(msg: &str) -> Self {
        Error::custom(format!("invalid value: {}", msg))
    }
}

///////////////////////////////////////////////////////////////////////////////

/// A trait that describes a type that can be serialized by a `Serializer`.
pub trait Serialize {
    /// Serializes this value into this serializer.
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer;
}

///////////////////////////////////////////////////////////////////////////////

/// A trait that describes a type that can serialize a stream of values into the underlying format.
pub trait Serializer {
    /// The error type that can be returned if some error occurs during serialization.
    type Error: Error;

    /// A state object that is initialized by `serialize_seq`, passed to
    /// `serialize_seq_elt`, and consumed by `serialize_seq_end`. Use `()` if no
    /// state is required.
    type SeqState;
    /// A state object that is initialized by `serialize_tuple`, passed to
    /// `serialize_tuple_elt`, and consumed by `serialize_tuple_end`. Use `()`
    /// if no state is required.
    type TupleState;
    /// A state object that is initialized by `serialize_tuple_struct`, passed
    /// to `serialize_tuple_struct_elt`, and consumed by
    /// `serialize_tuple_struct_end`. Use `()` if no state is required.
    type TupleStructState;
    /// A state object that is initialized by `serialize_tuple_variant`, passed
    /// to `serialize_tuple_variant_elt`, and consumed by
    /// `serialize_tuple_variant_end`. Use `()` if no state is required.
    type TupleVariantState;
    /// A state object that is initialized by `serialize_map`, passed to
    /// `serialize_map_elt`, and consumed by `serialize_map_end`. Use `()` if no
    /// state is required.
    type MapState;
    /// A state object that is initialized by `serialize_struct`, passed to
    /// `serialize_struct_elt`, and consumed by `serialize_struct_end`. Use `()`
    /// if no state is required.
    type StructState;
    /// A state object that is initialized by `serialize_struct_variant`, passed
    /// to `serialize_struct_variant_elt`, and consumed by
    /// `serialize_struct_variant_end`. Use `()` if no state is required.
    type StructVariantState;

    /// Serializes a `bool` value.
    fn serialize_bool(&mut self, v: bool) -> Result<(), Self::Error>;

    /// Serializes an `isize` value. If the format does not differentiate
    /// between `isize` and `i64`, a reasonable implementation would be to cast
    /// the value to `i64` and forward to `serialize_i64`.
    fn serialize_isize(&mut self, v: isize) -> Result<(), Self::Error>;

    /// Serializes an `i8` value. If the format does not differentiate between
    /// `i8` and `i64`, a reasonable implementation would be to cast the value
    /// to `i64` and forward to `serialize_i64`.
    fn serialize_i8(&mut self, v: i8) -> Result<(), Self::Error>;

    /// Serializes an `i16` value. If the format does not differentiate between
    /// `i16` and `i64`, a reasonable implementation would be to cast the value
    /// to `i64` and forward to `serialize_i64`.
    fn serialize_i16(&mut self, v: i16) -> Result<(), Self::Error>;

    /// Serializes an `i32` value. If the format does not differentiate between
    /// `i32` and `i64`, a reasonable implementation would be to cast the value
    /// to `i64` and forward to `serialize_i64`.
    fn serialize_i32(&mut self, v: i32) -> Result<(), Self::Error>;

    /// Serializes an `i64` value.
    fn serialize_i64(&mut self, v: i64) -> Result<(), Self::Error>;

    /// Serializes a `usize` value. If the format does not differentiate between
    /// `usize` and `u64`, a reasonable implementation would be to cast the
    /// value to `u64` and forward to `serialize_u64`.
    fn serialize_usize(&mut self, v: usize) -> Result<(), Self::Error>;

    /// Serializes a `u8` value. If the format does not differentiate between
    /// `u8` and `u64`, a reasonable implementation would be to cast the value
    /// to `u64` and forward to `serialize_u64`.
    fn serialize_u8(&mut self, v: u8) -> Result<(), Self::Error>;

    /// Serializes a `u16` value. If the format does not differentiate between
    /// `u16` and `u64`, a reasonable implementation would be to cast the value
    /// to `u64` and forward to `serialize_u64`.
    fn serialize_u16(&mut self, v: u16) -> Result<(), Self::Error>;

    /// Serializes a `u32` value. If the format does not differentiate between
    /// `u32` and `u64`, a reasonable implementation would be to cast the value
    /// to `u64` and forward to `serialize_u64`.
    fn serialize_u32(&mut self, v: u32) -> Result<(), Self::Error>;

    /// `Serializes a `u64` value.
    fn serialize_u64(&mut self, v: u64) -> Result<(), Self::Error>;

    /// Serializes an `f32` value. If the format does not differentiate between
    /// `f32` and `f64`, a reasonable implementation would be to cast the value
    /// to `f64` and forward to `serialize_f64`.
    fn serialize_f32(&mut self, v: f32) -> Result<(), Self::Error>;

    /// Serializes an `f64` value.
    fn serialize_f64(&mut self, v: f64) -> Result<(), Self::Error>;

    /// Serializes a character.
    fn serialize_char(&mut self, v: char) -> Result<(), Self::Error>;

    /// Serializes a `&str`.
    fn serialize_str(&mut self, value: &str) -> Result<(), Self::Error>;

    /// Enables serializers to serialize byte slices more compactly or more
    /// efficiently than other types of slices. If no efficient implementation
    /// is available, a reasonable implementation would be to forward to
    /// `serialize_seq`.
    fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error>;

    /// Serializes a `()` value.
    fn serialize_unit(&mut self) -> Result<(), Self::Error>;

    /// Serializes a unit struct value. A reasonable implementation would be to
    /// forward to `serialize_unit`.
    fn serialize_unit_struct(
        &mut self,
        name: &str,
    ) -> Result<(), Self::Error>;

    /// Serializes a unit variant, otherwise known as a variant with no
    /// arguments. A reasonable implementation would be to forward to
    /// `serialize_unit`.
    fn serialize_unit_variant(
        &mut self,
        name: &str,
        variant_index: usize,
        variant: &str,
    ) -> Result<(), Self::Error>;

    /// Allows a tuple struct with a single element, also known as a newtype
    /// struct, to be more efficiently serialized than a tuple struct with
    /// multiple items. A reasonable implementation would be to forward to
    /// `serialize_tuple_struct`.
    fn serialize_newtype_struct<T: Serialize>(
        &mut self,
        name: &str,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Allows a variant with a single item to be more efficiently serialized
    /// than a variant with multiple items. A reasonable implementation would be
    /// to forward to `serialize_tuple_variant`.
    fn serialize_newtype_variant<T: Serialize>(
        &mut self,
        name: &str,
        variant_index: usize,
        variant: &str,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Serializes a `None` value.
    fn serialize_none(&mut self) -> Result<(), Self::Error>;

    /// Serializes a `Some(...)` value.
    fn serialize_some<T: Serialize>(
        &mut self,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a sequence. This call must be followed by zero or
    /// more calls to `serialize_seq_elt`, then a call to `serialize_seq_end`.
    fn serialize_seq(
        &mut self,
        len: Option<usize>,
    ) -> Result<Self::SeqState, Self::Error>;

    /// Serializes a sequence element. Must have previously called
    /// `serialize_seq`.
    fn serialize_seq_elt<T: Serialize>(
        &mut self,
        state: &mut Self::SeqState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a sequence.
    fn serialize_seq_end(
        &mut self,
        state: Self::SeqState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a tuple. This call must be followed by zero or more
    /// calls to `serialize_tuple_elt`, then a call to `serialize_tuple_end`. A
    /// reasonable implementation would be to forward to `serialize_seq`.
    fn serialize_tuple(
        &mut self,
        len: usize,
    ) -> Result<Self::TupleState, Self::Error>;

    /// Serializes a tuple element. Must have previously called
    /// `serialize_tuple`.
    fn serialize_tuple_elt<T: Serialize>(
        &mut self,
        state: &mut Self::TupleState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a tuple.
    fn serialize_tuple_end(
        &mut self,
        state: Self::TupleState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a tuple struct. This call must be followed by zero
    /// or more calls to `serialize_tuple_struct_elt`, then a call to
    /// `serialize_tuple_struct_end`. A reasonable implementation would be to
    /// forward to `serialize_tuple`.
    fn serialize_tuple_struct(
        &mut self,
        name: &str,
        len: usize,
    ) -> Result<Self::TupleStructState, Self::Error>;

    /// Serializes a tuple struct element. Must have previously called
    /// `serialize_tuple_struct`.
    fn serialize_tuple_struct_elt<T: Serialize>(
        &mut self,
        state: &mut Self::TupleStructState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a tuple struct.
    fn serialize_tuple_struct_end(
        &mut self,
        state: Self::TupleStructState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a tuple variant. This call must be followed by zero
    /// or more calls to `serialize_tuple_variant_elt`, then a call to
    /// `serialize_tuple_variant_end`. A reasonable implementation would be to
    /// forward to `serialize_tuple_struct`.
    fn serialize_tuple_variant(
        &mut self,
        name: &str,
        variant_index: usize,
        variant: &str,
        len: usize,
    ) -> Result<Self::TupleVariantState, Self::Error>;

    /// Serializes a tuple variant element. Must have previously called
    /// `serialize_tuple_variant`.
    fn serialize_tuple_variant_elt<T: Serialize>(
        &mut self,
        state: &mut Self::TupleVariantState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a tuple variant.
    fn serialize_tuple_variant_end(
        &mut self,
        state: Self::TupleVariantState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a map. This call must be followed by zero or more
    /// calls to `serialize_map_elt`, then a call to `serialize_map_end`.
    fn serialize_map(
        &mut self,
        len: Option<usize>,
    ) -> Result<Self::MapState, Self::Error>;

    /// Serialize a map element. Must have previously called `serialize_map`.
    fn serialize_map_elt<K: Serialize, V: Serialize>(
        &mut self,
        state: &mut Self::MapState,
        key: K,
        value: V,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a map.
    fn serialize_map_end(
        &mut self,
        state: Self::MapState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a struct. This call must be followed by zero or more
    /// calls to `serialize_struct_elt`, then a call to `serialize_struct_end`.
    fn serialize_struct(
        &mut self,
        name: &str,
        len: usize,
    ) -> Result<Self::StructState, Self::Error>;

    /// Serializes a struct field. Must have previously called
    /// `serialize_struct`.
    fn serialize_struct_elt<V: Serialize>(
        &mut self,
        state: &mut Self::StructState,
        key: &str,
        value: V,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a struct.
    fn serialize_struct_end(
        &mut self,
        state: Self::StructState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a struct variant. This call must be followed by zero
    /// or more calls to `serialize_struct_variant_elt`, then a call to
    /// `serialize_struct_variant_end`.
    fn serialize_struct_variant(
        &mut self,
        name: &str,
        variant_index: usize,
        variant: &str,
        len: usize,
    ) -> Result<Self::StructVariantState, Self::Error>;

    /// Serialize a struct variant element. Must have previously called
    /// `serialize_struct_variant`.
    fn serialize_struct_variant_elt<V: Serialize>(
        &mut self,
        state: &mut Self::StructVariantState,
        key: &str,
        value: V,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a struct variant.
    fn serialize_struct_variant_end(
        &mut self,
        state: Self::StructVariantState,
    ) -> Result<(), Self::Error>;
}
<|endoftext|>


<commit_before>#![no_main]

use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    if data.len() <= 10240 {
        let _ = serde_yaml::from_slice::<serde_yaml::Value>(data);
    }
});
<commit_msg>Ignore using destructuring assignment to wildcard pattern<commit_after>#![no_main]

use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    if data.len() <= 10240 {
        _ = serde_yaml::from_slice::<serde_yaml::Value>(data);
    }
});
<|endoftext|>


<commit_before>macro_rules! toml_template {
    ($name: expr) => {
format_args!(r##"
[package]
name = "{0}-fuzz"
version = "0.0.1"
authors = ["Automatically generated"]
publish = false

[package.metadata]
cargo-fuzz = true

[dependencies.{0}]
path = ".."
[dependencies.libfuzzer-sys]
git = "https://github.com/rust-fuzz/libfuzzer-sys.git"

# Prevent this from interfering with workspaces
[workspace]
members = ["."]
"##, $name)
    }
}

macro_rules! toml_bin_template {
    ($name: expr) => {
format_args!(r#"
[[bin]]
name = "{0}"
path = "fuzz_targets/{0}.rs"
"#, $name)
    }
}

macro_rules! gitignore_template {
    () => {
format_args!(r##"
target
corpus
artifacts
"##)
    }
}

macro_rules! target_template {
    ($name: expr) => {
format_args!(r##"#![no_main]
#[macro_use] extern crate libfuzzer_sys;
extern crate {};

fuzz_target!(|data: &[u8]| {{
    // fuzzed code goes here
}});
"##, $name)
    }
}
<commit_msg>Update template.rs to conform to conventions<commit_after>macro_rules! toml_template {
    ($name: expr) => {
format_args!(r##"
[package]
name = "{0}-fuzz"
version = "0.0.0"
authors = ["Automatically generated"]
publish = false

[package.metadata]
cargo-fuzz = true

[dependencies.{0}]
path = ".."
[dependencies.libfuzzer-sys]
git = "https://github.com/rust-fuzz/libfuzzer-sys.git"

# Prevent this from interfering with workspaces
[workspace]
members = ["."]
"##, $name)
    }
}

macro_rules! toml_bin_template {
    ($name: expr) => {
format_args!(r#"
[[bin]]
name = "{0}"
path = "fuzz_targets/{0}.rs"
"#, $name)
    }
}

macro_rules! gitignore_template {
    () => {
format_args!(r##"
target
corpus
artifacts
"##)
    }
}

macro_rules! target_template {
    ($name: expr) => {
format_args!(r##"#![no_main]
#[macro_use] extern crate libfuzzer_sys;
extern crate {};

fuzz_target!(|data: &[u8]| {{
    // fuzzed code goes here
}});
"##, $name)
    }
}
<|endoftext|>


<commit_before><commit_msg>slower walk speed<commit_after><|endoftext|>


<commit_before>use crate::code_pair_put_back::CodePairPutBack;

use crate::{CodePair, DxfError, DxfResult};

use std::io::Read;

const FILE_HEADER_LENGTH: usize = 14;
const FILE_LENGTH_OFFSET: usize = 2;
const IMAGE_DATA_OFFSET_OFFSET: usize = 10;

const BITMAPINFOHEADER_SIZE: usize = 40;

pub(crate) fn read_thumbnail<T>(
    iter: &mut CodePairPutBack<T>,
) -> DxfResult<Option<image::DynamicImage>>
where
    T: Read,
{
    match read_thumbnail_bytes_from_code_pairs(iter)? {
        Some(mut data) => {
            if update_thumbnail_data_offset_in_situ(&mut data)? {
                read_thumbnail_from_bytes(&data)
            } else {
                Ok(None)
            }
        }
        None => Ok(None),
    }
}

fn read_thumbnail_bytes_from_code_pairs<T>(
    iter: &mut CodePairPutBack<T>,
) -> DxfResult<Option<Vec<u8>>>
where
    T: Read,
{
    // get the length; we don't really care about this since we'll just read whatever's there
    let _length = match iter.next() {
        Some(Ok(pair @ CodePair { code: 0, .. })) => {
            // likely 0/ENDSEC
            iter.put_back(Ok(pair));
            return Ok(None);
        }
        Some(Ok(pair @ CodePair { code: 90, .. })) => pair.assert_i32()? as usize,
        Some(Ok(pair)) => {
            return Err(DxfError::UnexpectedCode(pair.code, pair.offset));
        }
        Some(Err(e)) => return Err(e),
        None => return Ok(None),
    };

    // prepend the BMP header that always seems to be missing from DXF files
    let mut data: Vec<u8> = vec![
        b'B', b'M', // magic number
        0x00, 0x00, 0x00, 0x00, // file length (set below)
        0x00, 0x00, // reserved
        0x00, 0x00, // reserved
        0x00, 0x00, 0x00, 0x00, // image data offset (calculated elsewhere)
    ];

    // read the hex data
    loop {
        match iter.next() {
            Some(Ok(pair @ CodePair { code: 0, .. })) => {
                // likely 0/ENDSEC
                iter.put_back(Ok(pair));
                break;
            }
            Some(Ok(pair @ CodePair { code: 310, .. })) => {
                let line_data = pair.assert_binary()?;
                for b in line_data {
                    data.push(b);
                }
            }
            Some(Ok(pair)) => {
                return Err(DxfError::UnexpectedCode(pair.code, pair.offset));
            }
            Some(Err(e)) => return Err(e),
            None => break,
        }
    }

    let file_length = data.len();
    set_i32(&mut data, FILE_LENGTH_OFFSET, file_length as i32)?;
    Ok(Some(data))
}

fn update_thumbnail_data_offset_in_situ(data: &mut Vec<u8>) -> DxfResult<bool> {
    // calculate the image data offset
    let dib_header_size = get_i32(&data, FILE_HEADER_LENGTH)? as usize;

    // calculate the palette size
    let palette_size = match dib_header_size {
        BITMAPINFOHEADER_SIZE => {
            let palette_color_count = get_u32(&data, FILE_HEADER_LENGTH + 32)? as usize;
            palette_color_count * 4 // always 4 bytes: BGRA
        }
        _ => return Ok(false),
    };

    // set the image data offset
    let image_data_offset = FILE_HEADER_LENGTH + dib_header_size + palette_size;
    set_i32(data, IMAGE_DATA_OFFSET_OFFSET, image_data_offset as i32)?;

    Ok(true)
}

#[test]
fn set_thumbnail_offset_for_bitmapinfoheader_non_palette() {
    let mut data: Vec<u8> = vec![
        b'B', b'M', // magic number
        0x00, 0x00, 0x00, 0x00, // file length; not needed for this test
        0x00, 0x00, // reserved
        0x00, 0x00, // reserved
        0x00, 0x00, 0x00, 0x00, // the image data offset that will be filled in
        0x28, 0x00, 0x00, 0x00, // BITMAPINFOHEADER length
        0x00, 0x00, 0x00, 0x00, // width (not needed)
        0x00, 0x00, 0x00, 0x00, // height (not needed)
        0x00, 0x00, // color planes (not needed)
        0x00, 0x00, // bits per pixel (not needed)
        0x00, 0x00, 0x00, 0x00, // compression (not needed)
        0x00, 0x00, 0x00, 0x00, // image size (not needed)
        0x00, 0x00, 0x00, 0x00, // horizontal resolution (not needed)
        0x00, 0x00, 0x00, 0x00, // vertical resolution (not needed)
        0x00, 0x00, 0x00, 0x00, // color palette count (0 means default of 2^n)
        0x00, 0x00, 0x00, 0x00, // important colors used (not needed)
    ];
    assert!(update_thumbnail_data_offset_in_situ(&mut data).unwrap());
    assert_eq!(0x36, get_i32(&data, IMAGE_DATA_OFFSET_OFFSET).unwrap());
}

#[test]
fn set_thumbnail_offset_for_bitmapinfoheader_palette_256() {
    let mut data: Vec<u8> = vec![
        b'B', b'M', // magic number
        0x00, 0x00, 0x00, 0x00, // file length; not needed for this test
        0x00, 0x00, // reserved
        0x00, 0x00, // reserved
        0x00, 0x00, 0x00, 0x00, // the image data offset that will be filled in
        0x28, 0x00, 0x00, 0x00, // BITMAPINFOHEADER length
        0x00, 0x00, 0x00, 0x00, // width (not needed)
        0x00, 0x00, 0x00, 0x00, // height (not needed)
        0x00, 0x00, // color planes (not needed)
        0x00, 0x00, // bits per pixel (not needed)
        0x00, 0x00, 0x00, 0x00, // compression (not needed)
        0x00, 0x00, 0x00, 0x00, // image size (not needed)
        0x00, 0x00, 0x00, 0x00, // horizontal resolution (not needed)
        0x00, 0x00, 0x00, 0x00, // vertical resolution (not needed)
        0xFF, 0x00, 0x00, 0x00, // color palette count (0 means default of 2^n)
        0x00, 0x00, 0x00, 0x00, // important colors used (not needed)
    ];
    assert!(update_thumbnail_data_offset_in_situ(&mut data).unwrap());
    assert_eq!(0x0432, get_i32(&data, IMAGE_DATA_OFFSET_OFFSET).unwrap());
}

fn read_thumbnail_from_bytes(data: &[u8]) -> DxfResult<Option<image::DynamicImage>> {
    let image = image::load_from_memory(&data)?;
    Ok(Some(image))
}

fn get_i32(data: &[u8], offset: usize) -> DxfResult<i32> {
    let expected_length = offset + 4;
    if data.len() < expected_length {
        return Err(DxfError::UnexpectedEndOfInput);
    }

    let value = data[offset] as i32
        + ((data[offset + 1] as i32) << 8)
        + ((data[offset + 2] as i32) << 16)
        + ((data[offset + 3] as i32) << 24);
    Ok(value)
}

#[test]
fn test_get_i32() {
    let data: Vec<u8> = vec![0x00, 0x78, 0x56, 0x34, 0x12, 0x00];
    let value = get_i32(&data, 1).unwrap();
    assert_eq!(0x12345678, value);
}

fn get_u32(data: &[u8], offset: usize) -> DxfResult<u32> {
    let expected_length = offset + 4;
    if data.len() < expected_length {
        return Err(DxfError::UnexpectedEndOfInput);
    }

    let value = data[offset] as u32
        + ((data[offset + 1] as u32) << 8)
        + ((data[offset + 2] as u32) << 16)
        + ((data[offset + 3] as u32) << 24);
    Ok(value)
}

#[test]
fn test_get_u32() {
    let data: Vec<u8> = vec![0x00, 0x78, 0x56, 0x34, 0x12, 0x00];
    let value = get_u32(&data, 1).unwrap();
    assert_eq!(0x12345678, value);
}

fn set_i32(data: &mut Vec<u8>, offset: usize, value: i32) -> DxfResult<()> {
    let expected_length = offset + 4;
    if data.len() < expected_length {
        return Err(DxfError::UnexpectedEndOfInput);
    }

    data[offset] = value as u8;
    data[offset + 1] = (value >> 8) as u8;
    data[offset + 2] = (value >> 16) as u8;
    data[offset + 3] = (value >> 24) as u8;
    Ok(())
}

#[test]
fn test_set_i32() {
    let mut data = vec![0x00u8; 6];
    set_i32(&mut data, 1, 0x12345678).unwrap();
    assert_eq!(vec![0x00, 0x78, 0x56, 0x34, 0x12, 0x00], data);
}
<commit_msg>enable thumbnail with BITMAPV4HEADER<commit_after>use crate::code_pair_put_back::CodePairPutBack;

use crate::{CodePair, DxfError, DxfResult};

use std::io::Read;

const FILE_HEADER_LENGTH: usize = 14;
const FILE_LENGTH_OFFSET: usize = 2;
const IMAGE_DATA_OFFSET_OFFSET: usize = 10;

const BITMAPINFOHEADER_SIZE: usize = 40;
const BITMAPV4HEADER_SIZE: usize = 108;

pub(crate) fn read_thumbnail<T>(
    iter: &mut CodePairPutBack<T>,
) -> DxfResult<Option<image::DynamicImage>>
where
    T: Read,
{
    match read_thumbnail_bytes_from_code_pairs(iter)? {
        Some(mut data) => {
            if update_thumbnail_data_offset_in_situ(&mut data)? {
                read_thumbnail_from_bytes(&data)
            } else {
                Ok(None)
            }
        }
        None => Ok(None),
    }
}

fn read_thumbnail_bytes_from_code_pairs<T>(
    iter: &mut CodePairPutBack<T>,
) -> DxfResult<Option<Vec<u8>>>
where
    T: Read,
{
    // get the length; we don't really care about this since we'll just read whatever's there
    let _length = match iter.next() {
        Some(Ok(pair @ CodePair { code: 0, .. })) => {
            // likely 0/ENDSEC
            iter.put_back(Ok(pair));
            return Ok(None);
        }
        Some(Ok(pair @ CodePair { code: 90, .. })) => pair.assert_i32()? as usize,
        Some(Ok(pair)) => {
            return Err(DxfError::UnexpectedCode(pair.code, pair.offset));
        }
        Some(Err(e)) => return Err(e),
        None => return Ok(None),
    };

    // prepend the BMP header that always seems to be missing from DXF files
    let mut data: Vec<u8> = vec![
        b'B', b'M', // magic number
        0x00, 0x00, 0x00, 0x00, // file length (set below)
        0x00, 0x00, // reserved
        0x00, 0x00, // reserved
        0x00, 0x00, 0x00, 0x00, // image data offset (calculated elsewhere)
    ];

    // read the hex data
    loop {
        match iter.next() {
            Some(Ok(pair @ CodePair { code: 0, .. })) => {
                // likely 0/ENDSEC
                iter.put_back(Ok(pair));
                break;
            }
            Some(Ok(pair @ CodePair { code: 310, .. })) => {
                let line_data = pair.assert_binary()?;
                for b in line_data {
                    data.push(b);
                }
            }
            Some(Ok(pair)) => {
                return Err(DxfError::UnexpectedCode(pair.code, pair.offset));
            }
            Some(Err(e)) => return Err(e),
            None => break,
        }
    }

    let file_length = data.len();
    set_i32(&mut data, FILE_LENGTH_OFFSET, file_length as i32)?;
    Ok(Some(data))
}

fn update_thumbnail_data_offset_in_situ(data: &mut Vec<u8>) -> DxfResult<bool> {
    // calculate the image data offset
    let dib_header_size = get_i32(&data, FILE_HEADER_LENGTH)? as usize;

    // calculate the palette size
    let palette_size = match dib_header_size {
        BITMAPINFOHEADER_SIZE | BITMAPV4HEADER_SIZE => {
            let palette_color_count = get_u32(&data, FILE_HEADER_LENGTH + 32)? as usize;
            palette_color_count * 4 // always 4 bytes: BGRA
        }
        _ => return Ok(false),
    };

    // set the image data offset
    let image_data_offset = FILE_HEADER_LENGTH + dib_header_size + palette_size;
    set_i32(data, IMAGE_DATA_OFFSET_OFFSET, image_data_offset as i32)?;

    Ok(true)
}

#[test]
fn set_thumbnail_offset_for_bitmapinfoheader_non_palette() {
    let mut data: Vec<u8> = vec![
        b'B', b'M', // magic number
        0x00, 0x00, 0x00, 0x00, // file length; not needed for this test
        0x00, 0x00, // reserved
        0x00, 0x00, // reserved
        0x00, 0x00, 0x00, 0x00, // the image data offset that will be filled in
        0x28, 0x00, 0x00, 0x00, // BITMAPINFOHEADER length
        0x00, 0x00, 0x00, 0x00, // width (not needed)
        0x00, 0x00, 0x00, 0x00, // height (not needed)
        0x00, 0x00, // color planes (not needed)
        0x00, 0x00, // bits per pixel (not needed)
        0x00, 0x00, 0x00, 0x00, // compression (not needed)
        0x00, 0x00, 0x00, 0x00, // image size (not needed)
        0x00, 0x00, 0x00, 0x00, // horizontal resolution (not needed)
        0x00, 0x00, 0x00, 0x00, // vertical resolution (not needed)
        0x00, 0x00, 0x00, 0x00, // color palette count (0 means default of 2^n)
        0x00, 0x00, 0x00, 0x00, // important colors used (not needed)
    ];
    assert!(update_thumbnail_data_offset_in_situ(&mut data).unwrap());
    assert_eq!(0x36, get_i32(&data, IMAGE_DATA_OFFSET_OFFSET).unwrap());
}

#[test]
fn set_thumbnail_offset_for_bitmapinfoheader_palette_256() {
    let mut data: Vec<u8> = vec![
        b'B', b'M', // magic number
        0x00, 0x00, 0x00, 0x00, // file length; not needed for this test
        0x00, 0x00, // reserved
        0x00, 0x00, // reserved
        0x00, 0x00, 0x00, 0x00, // the image data offset that will be filled in
        0x28, 0x00, 0x00, 0x00, // BITMAPINFOHEADER length
        0x00, 0x00, 0x00, 0x00, // width (not needed)
        0x00, 0x00, 0x00, 0x00, // height (not needed)
        0x00, 0x00, // color planes (not needed)
        0x00, 0x00, // bits per pixel (not needed)
        0x00, 0x00, 0x00, 0x00, // compression (not needed)
        0x00, 0x00, 0x00, 0x00, // image size (not needed)
        0x00, 0x00, 0x00, 0x00, // horizontal resolution (not needed)
        0x00, 0x00, 0x00, 0x00, // vertical resolution (not needed)
        0xFF, 0x00, 0x00, 0x00, // color palette count (0 means default of 2^n)
        0x00, 0x00, 0x00, 0x00, // important colors used (not needed)
    ];
    assert!(update_thumbnail_data_offset_in_situ(&mut data).unwrap());
    assert_eq!(0x0432, get_i32(&data, IMAGE_DATA_OFFSET_OFFSET).unwrap());
}

#[test]
fn set_thumbnail_offset_for_bitmapv4header_non_palette() {
    let mut data: Vec<u8> = vec![
        b'B', b'M', // magic number
        0x00, 0x00, 0x00, 0x00, // file length; not needed for this test
        0x00, 0x00, // reserved
        0x00, 0x00, // reserved
        0x00, 0x00, 0x00, 0x00, // the image data offset that will be filled in
        0x6C, 0x00, 0x00, 0x00, // BITMAPV4HEADER length
        0x00, 0x00, 0x00, 0x00, // width (not needed)
        0x00, 0x00, 0x00, 0x00, // height (not needed)
        0x00, 0x00, // color planes (not needed)
        0x00, 0x00, // bits per pixel (not needed)
        0x00, 0x00, 0x00, 0x00, // compression (not needed)
        0x00, 0x00, 0x00, 0x00, // image size (not needed)
        0x00, 0x00, 0x00, 0x00, // horizontal resolution (not needed)
        0x00, 0x00, 0x00, 0x00, // vertical resolution (not needed)
        0x00, 0x00, 0x00, 0x00, // color palette count (0 means default of 2^n)
        0x00, 0x00, 0x00, 0x00, // important colors used (not needed)
        0x00, 0x00, 0x00, 0x00, // red mask
        0x00, 0x00, 0x00, 0x00, // green mask
        0x00, 0x00, 0x00, 0x00, // blue mask
        0x00, 0x00, 0x00, 0x00, // alpha mask
        0x00, 0x00, 0x00, 0x00, // color space type
        0x00, 0x00, 0x00, 0x00, // red triple
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, // green triple
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, // blue triple
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, // gamma red
        0x00, 0x00, 0x00, 0x00, // gamma green
        0x00, 0x00, 0x00, 0x00, // gamma blue
    ];
    assert!(update_thumbnail_data_offset_in_situ(&mut data).unwrap());
    assert_eq!(0x7A, get_i32(&data, IMAGE_DATA_OFFSET_OFFSET).unwrap());
}

#[test]
fn set_thumbnail_offset_for_bitmapv4header_palette_256() {
    let mut data: Vec<u8> = vec![
        b'B', b'M', // magic number
        0x00, 0x00, 0x00, 0x00, // file length; not needed for this test
        0x00, 0x00, // reserved
        0x00, 0x00, // reserved
        0x00, 0x00, 0x00, 0x00, // the image data offset that will be filled in
        0x6C, 0x00, 0x00, 0x00, // BITMAPV4HEADER length
        0x00, 0x00, 0x00, 0x00, // width (not needed)
        0x00, 0x00, 0x00, 0x00, // height (not needed)
        0x00, 0x00, // color planes (not needed)
        0x00, 0x00, // bits per pixel (not needed)
        0x00, 0x00, 0x00, 0x00, // compression (not needed)
        0x00, 0x00, 0x00, 0x00, // image size (not needed)
        0x00, 0x00, 0x00, 0x00, // horizontal resolution (not needed)
        0x00, 0x00, 0x00, 0x00, // vertical resolution (not needed)
        0xFF, 0x00, 0x00, 0x00, // color palette count (0 means default of 2^n)
        0x00, 0x00, 0x00, 0x00, // important colors used (not needed)
        0x00, 0x00, 0x00, 0x00, // red mask
        0x00, 0x00, 0x00, 0x00, // green mask
        0x00, 0x00, 0x00, 0x00, // blue mask
        0x00, 0x00, 0x00, 0x00, // alpha mask
        0x00, 0x00, 0x00, 0x00, // color space type
        0x00, 0x00, 0x00, 0x00, // red triple
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, // green triple
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, // blue triple
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, //
        0x00, 0x00, 0x00, 0x00, // gamma red
        0x00, 0x00, 0x00, 0x00, // gamma green
        0x00, 0x00, 0x00, 0x00, // gamma blue
    ];
    assert!(update_thumbnail_data_offset_in_situ(&mut data).unwrap());
    assert_eq!(0x0476, get_i32(&data, IMAGE_DATA_OFFSET_OFFSET).unwrap());
}

fn read_thumbnail_from_bytes(data: &[u8]) -> DxfResult<Option<image::DynamicImage>> {
    let image = image::load_from_memory(&data)?;
    Ok(Some(image))
}

fn get_i32(data: &[u8], offset: usize) -> DxfResult<i32> {
    let expected_length = offset + 4;
    if data.len() < expected_length {
        return Err(DxfError::UnexpectedEndOfInput);
    }

    let value = data[offset] as i32
        + ((data[offset + 1] as i32) << 8)
        + ((data[offset + 2] as i32) << 16)
        + ((data[offset + 3] as i32) << 24);
    Ok(value)
}

#[test]
fn test_get_i32() {
    let data: Vec<u8> = vec![0x00, 0x78, 0x56, 0x34, 0x12, 0x00];
    let value = get_i32(&data, 1).unwrap();
    assert_eq!(0x12345678, value);
}

fn get_u32(data: &[u8], offset: usize) -> DxfResult<u32> {
    let expected_length = offset + 4;
    if data.len() < expected_length {
        return Err(DxfError::UnexpectedEndOfInput);
    }

    let value = data[offset] as u32
        + ((data[offset + 1] as u32) << 8)
        + ((data[offset + 2] as u32) << 16)
        + ((data[offset + 3] as u32) << 24);
    Ok(value)
}

#[test]
fn test_get_u32() {
    let data: Vec<u8> = vec![0x00, 0x78, 0x56, 0x34, 0x12, 0x00];
    let value = get_u32(&data, 1).unwrap();
    assert_eq!(0x12345678, value);
}

fn set_i32(data: &mut Vec<u8>, offset: usize, value: i32) -> DxfResult<()> {
    let expected_length = offset + 4;
    if data.len() < expected_length {
        return Err(DxfError::UnexpectedEndOfInput);
    }

    data[offset] = value as u8;
    data[offset + 1] = (value >> 8) as u8;
    data[offset + 2] = (value >> 16) as u8;
    data[offset + 3] = (value >> 24) as u8;
    Ok(())
}

#[test]
fn test_set_i32() {
    let mut data = vec![0x00u8; 6];
    set_i32(&mut data, 1, 0x12345678).unwrap();
    assert_eq!(vec![0x00, 0x78, 0x56, 0x34, 0x12, 0x00], data);
}
<|endoftext|>


<commit_before>pub enum Token {
    Comma,
    Number(f64),
    ParenClose,
    ParenOpen,
    Word(String),
}

pub fn tokenize(input: &str) -> Tokenizer {
    Tokenizer {text: String::from_str(input)}
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\n' | '\r' | '\t' | ' ' => true,
        _                        => false,
    }
}

fn is_numberlike(c: char) -> bool {
    match c {
        c if c.is_numeric() => true,
        '.' | '-'           => true,
        _                   => false,
    }
}

struct Tokenizer {
    text: String
}

impl Iterator<Token> for Tokenizer {
    fn next(&mut self) -> Option<Token> {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return None
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' => None,
            '(' => Some(Token::ParenOpen),
            ')' => Some(Token::ParenClose),
            ',' => Some(Token::Comma),
            c if is_whitespace(c) => self.next(),
            c if is_numberlike(c) => {
                let number = c.to_string() + self.read_until_whitespace().as_slice();
                let x: f64 = number.parse().unwrap();
                Some(Token::Number(x))
            }
            c => {
                let word = c.to_string() + self.read_until_whitespace().as_slice();
                Some(Token::Word(word))
            }
        }
    }
}

impl Tokenizer {
    fn pop_char(&mut self) -> Option<char> {
        if self.text.is_empty() {
            None
        } else {
            self.text.remove(0)
        }
    }

    fn read_until_whitespace(&mut self) -> String {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return "".to_string()
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' | '(' | ')' | ',' => {
                self.text.insert(0, next_char);
                "".to_string()
            }
            c if is_whitespace(c) => "".to_string(),
            _ => next_char.to_string() + self.read_until_whitespace().as_slice(),
        }
    }
}

#[test]
fn test_tokenizer_1word() {
    let test_str = "hello";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2words() {
    let test_str = "hello world";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "world"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_1number() {
    let test_str = "4.2";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "4.2"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2numbers() {
    let test_str = ".38 -2";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "0.38"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "-2"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}
<commit_msg>Add test for tokenizing WKT POINT<commit_after>pub enum Token {
    Comma,
    Number(f64),
    ParenClose,
    ParenOpen,
    Word(String),
}

pub fn tokenize(input: &str) -> Tokenizer {
    Tokenizer {text: String::from_str(input)}
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\n' | '\r' | '\t' | ' ' => true,
        _                        => false,
    }
}

fn is_numberlike(c: char) -> bool {
    match c {
        c if c.is_numeric() => true,
        '.' | '-'           => true,
        _                   => false,
    }
}

struct Tokenizer {
    text: String
}

impl Iterator<Token> for Tokenizer {
    fn next(&mut self) -> Option<Token> {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return None
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' => None,
            '(' => Some(Token::ParenOpen),
            ')' => Some(Token::ParenClose),
            ',' => Some(Token::Comma),
            c if is_whitespace(c) => self.next(),
            c if is_numberlike(c) => {
                let number = c.to_string() + self.read_until_whitespace().as_slice();
                let x: f64 = number.parse().unwrap();
                Some(Token::Number(x))
            }
            c => {
                let word = c.to_string() + self.read_until_whitespace().as_slice();
                Some(Token::Word(word))
            }
        }
    }
}

impl Tokenizer {
    fn pop_char(&mut self) -> Option<char> {
        if self.text.is_empty() {
            None
        } else {
            self.text.remove(0)
        }
    }

    fn read_until_whitespace(&mut self) -> String {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return "".to_string()
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' | '(' | ')' | ',' => {
                self.text.insert(0, next_char);
                "".to_string()
            }
            c if is_whitespace(c) => "".to_string(),
            _ => next_char.to_string() + self.read_until_whitespace().as_slice(),
        }
    }
}

#[test]
fn test_tokenizer_1word() {
    let test_str = "hello";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2words() {
    let test_str = "hello world";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "world"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_1number() {
    let test_str = "4.2";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "4.2"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2numbers() {
    let test_str = ".38 -2";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "0.38"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "-2"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_point() {
    let test_str = "POINT (10 -20)";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "POINT"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::ParenOpen => (),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "10"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "-20"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::ParenClose => (),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}
<|endoftext|>