<commit_before>#[cfg(test)]
mod create_table_query_typer {
    use expectest::prelude::be_ok;

    use sql::lexer::tokenize;
    use sql::parser::parse;
    use sql::query_typer::type_inferring;
    use sql::ast::{TypedStatement, Type};
    use sql::ast::create_table::{CreateTableQuery, ColumnTable};
    use sql::catalog_manager::LockBasedCatalogManager;

    #[test]
    fn default_size_for_char_should_be_255() {
        let catalog_manager = LockBasedCatalogManager::default();

        expect!(
            tokenize("create table tab1 (col1 char);")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Create(
                    CreateTableQuery::new(
                        "tab1",
                        vec![ColumnTable::new("col1", Type::Character(Option::from(255)), false, None, true, None)]
                    )
                )
            )
        );
    }

    #[test]
    fn list_of_columns_with_default_char_size() {
        let catalog_manager = LockBasedCatalogManager::default();

        expect!(
            tokenize("create table tab1 (col1 char, col2 char, col3 char);")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Create(
                    CreateTableQuery::new(
                        "tab1",
                        vec![
                            ColumnTable::new("col1", Type::Character(Option::from(255)), false, None, true, None),
                            ColumnTable::new("col2", Type::Character(Option::from(255)), false, None, true, None),
                            ColumnTable::new("col3", Type::Character(Option::from(255)), false, None, true, None)
                        ]
                    )
                )
            )
        );
    }
}

#[cfg(test)]
mod insert_query_typer {
    use expectest::prelude::be_ok;

    use sql::lexer::tokenize;
    use sql::parser::parse;
    use sql::query_typer::type_inferring;
    use sql::ast::{Type, TypedStatement};
    use sql::ast::insert_query::{InsertQuery, Value, ValueSource};
    use sql::catalog_manager::LockBasedCatalogManager;

    #[test]
    fn populates_columns_for_insert_query() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table2");
        catalog_manager.add_column_to("table2", ("col1", Type::Integer, None));
        catalog_manager.add_column_to("table2", ("col2", Type::Integer, None));
        catalog_manager.add_column_to("table2", ("col3", Type::Integer, None));

        expect!(
            tokenize("insert into table2 values (1, 2, 3);")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Insert(
                    InsertQuery::new(
                        "table2",
                        vec!["col1", "col2", "col3"],
                        ValueSource::Row(vec![Value::num("1"), Value::num("2"), Value::num("3")])
                    )
                )
            )
        );
    }

    #[test]
    fn populates_only_missed_column() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table_1");
        catalog_manager.add_column_to("table_1", ("col1", Type::Integer, Some("1")));
        catalog_manager.add_column_to("table_1", ("col2", Type::Integer, None));

        expect!(
            tokenize("insert into table_1 (col2) values (2);")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Insert(
                    InsertQuery::new(
                        "table_1",
                        vec!["col2", "col1"],
                        ValueSource::Row(vec![Value::num("2"), Value::num("1")])
                    )
                )
            )
        );
    }

    #[test]
    fn populates_default_value_for_different_types() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table_2");
        catalog_manager.add_column_to("table_2", ("col1", Type::Integer, Some("1")));
        catalog_manager.add_column_to("table_2", ("col2", Type::Integer, None));
        catalog_manager.add_column_to("table_2", ("col3", Type::Character(Option::from(3)), Some("str")));

        expect!(
            tokenize("insert into table_2 (col2) values (2);")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Insert(
                    InsertQuery::new(
                        "table_2",
                        vec!["col2", "col1", "col3"],
                        ValueSource::Row(vec![Value::num("2"), Value::num("1"), Value::str("str")])
                    )
                )
            )
        );
    }
}

#[cfg(test)]
mod select_query_typer {
    use expectest::prelude::be_ok;

    use sql::catalog_manager::LockBasedCatalogManager;

    use sql::lexer::tokenize;
    use sql::parser::parse;
    use sql::query_typer::type_inferring;

    use sql::ast::{Type, TypedStatement};
    use sql::ast::select_query::TypedSelectQuery;

    #[test]
    fn single_column_query() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table_1");
        catalog_manager.add_column_to("table_1", ("col1", Type::Integer, None));

        expect!(
            tokenize("select col1 from table_1;")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Select(
                    TypedSelectQuery::new("table_1", vec![("col1", Type::Integer)], None)
                )
            )
        );
    }

    #[test]
    fn multiple_columns_query() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table_3");
        catalog_manager.add_column_to("table_3", ("col2", Type::Integer, None));
        catalog_manager.add_column_to("table_3", ("col3", Type::Character(Some(10)), None));
        catalog_manager.add_column_to("table_3", ("col5", Type::Integer, None));

        expect!(
            tokenize("select col2, col3, col5 from table_3;")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Select(
                    TypedSelectQuery::new(
                        "table_3",
                        vec![
                            ("col2", Type::Integer),
                            ("col3", Type::Character(Some(10))),
                            ("col5", Type::Integer)
                        ],
                        None
                    )
                )
            )
        );
    }
}
<commit_msg>test for typed select query with not all column of a table<commit_after>#[cfg(test)]
mod create_table_query_typer {
    use expectest::prelude::be_ok;

    use sql::lexer::tokenize;
    use sql::parser::parse;
    use sql::query_typer::type_inferring;
    use sql::ast::{TypedStatement, Type};
    use sql::ast::create_table::{CreateTableQuery, ColumnTable};
    use sql::catalog_manager::LockBasedCatalogManager;

    #[test]
    fn default_size_for_char_should_be_255() {
        let catalog_manager = LockBasedCatalogManager::default();

        expect!(
            tokenize("create table tab1 (col1 char);")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Create(
                    CreateTableQuery::new(
                        "tab1",
                        vec![ColumnTable::new("col1", Type::Character(Option::from(255)), false, None, true, None)]
                    )
                )
            )
        );
    }

    #[test]
    fn list_of_columns_with_default_char_size() {
        let catalog_manager = LockBasedCatalogManager::default();

        expect!(
            tokenize("create table tab1 (col1 char, col2 char, col3 char);")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Create(
                    CreateTableQuery::new(
                        "tab1",
                        vec![
                            ColumnTable::new("col1", Type::Character(Option::from(255)), false, None, true, None),
                            ColumnTable::new("col2", Type::Character(Option::from(255)), false, None, true, None),
                            ColumnTable::new("col3", Type::Character(Option::from(255)), false, None, true, None)
                        ]
                    )
                )
            )
        );
    }
}

#[cfg(test)]
mod insert_query_typer {
    use expectest::prelude::be_ok;

    use sql::lexer::tokenize;
    use sql::parser::parse;
    use sql::query_typer::type_inferring;
    use sql::ast::{Type, TypedStatement};
    use sql::ast::insert_query::{InsertQuery, Value, ValueSource};
    use sql::catalog_manager::LockBasedCatalogManager;

    #[test]
    fn populates_columns_for_insert_query() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table2");
        catalog_manager.add_column_to("table2", ("col1", Type::Integer, None));
        catalog_manager.add_column_to("table2", ("col2", Type::Integer, None));
        catalog_manager.add_column_to("table2", ("col3", Type::Integer, None));

        expect!(
            tokenize("insert into table2 values (1, 2, 3);")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Insert(
                    InsertQuery::new(
                        "table2",
                        vec!["col1", "col2", "col3"],
                        ValueSource::Row(vec![Value::num("1"), Value::num("2"), Value::num("3")])
                    )
                )
            )
        );
    }

    #[test]
    fn populates_only_missed_column() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table_1");
        catalog_manager.add_column_to("table_1", ("col1", Type::Integer, Some("1")));
        catalog_manager.add_column_to("table_1", ("col2", Type::Integer, None));

        expect!(
            tokenize("insert into table_1 (col2) values (2);")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Insert(
                    InsertQuery::new(
                        "table_1",
                        vec!["col2", "col1"],
                        ValueSource::Row(vec![Value::num("2"), Value::num("1")])
                    )
                )
            )
        );
    }

    #[test]
    fn populates_default_value_for_different_types() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table_2");
        catalog_manager.add_column_to("table_2", ("col1", Type::Integer, Some("1")));
        catalog_manager.add_column_to("table_2", ("col2", Type::Integer, None));
        catalog_manager.add_column_to("table_2", ("col3", Type::Character(Option::from(3)), Some("str")));

        expect!(
            tokenize("insert into table_2 (col2) values (2);")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Insert(
                    InsertQuery::new(
                        "table_2",
                        vec!["col2", "col1", "col3"],
                        ValueSource::Row(vec![Value::num("2"), Value::num("1"), Value::str("str")])
                    )
                )
            )
        );
    }
}

#[cfg(test)]
mod select_query_typer {
    use expectest::prelude::be_ok;

    use sql::catalog_manager::LockBasedCatalogManager;

    use sql::lexer::tokenize;
    use sql::parser::parse;
    use sql::query_typer::type_inferring;

    use sql::ast::{Type, TypedStatement};
    use sql::ast::select_query::TypedSelectQuery;

    #[test]
    fn single_column_query() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table_1");
        catalog_manager.add_column_to("table_1", ("col1", Type::Integer, None));

        expect!(
            tokenize("select col1 from table_1;")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Select(
                    TypedSelectQuery::new("table_1", vec![("col1", Type::Integer)], None)
                )
            )
        );
    }

    #[test]
    fn multiple_columns_query() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table_3");
        catalog_manager.add_column_to("table_3", ("col2", Type::Integer, None));
        catalog_manager.add_column_to("table_3", ("col3", Type::Character(Some(10)), None));
        catalog_manager.add_column_to("table_3", ("col5", Type::Integer, None));

        expect!(
            tokenize("select col2, col3, col5 from table_3;")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Select(
                    TypedSelectQuery::new(
                        "table_3",
                        vec![
                            ("col2", Type::Integer),
                            ("col3", Type::Character(Some(10))),
                            ("col5", Type::Integer)
                        ],
                        None
                    )
                )
            )
        );
    }

    #[test]
    fn not_all_columns() {
        let catalog_manager = LockBasedCatalogManager::default();

        catalog_manager.add_table("table_2");
        catalog_manager.add_column_to("table_2", ("col1", Type::Integer, None));
        catalog_manager.add_column_to("table_2", ("col2", Type::Integer, None));
        catalog_manager.add_column_to("table_2", ("col3", Type::Integer, None));

        expect!(
            tokenize("select col1, col3 from table_2;")
                .and_then(parse)
                .and_then(|statement| type_inferring(catalog_manager, statement))
        ).to(
            be_ok().value(
                TypedStatement::Select(
                    TypedSelectQuery::new(
                        "table_2",
                        vec![
                            ("col1", Type::Integer),
                            ("col3", Type::Integer)
                        ],
                        None
                    )
                )
            )
        );
    }
}
<|endoftext|>


<commit_before>use std::convert::AsRef;
use cripes::symbol::{Pool,Type,Unpacked,Inline,PackFormat};
use std::string::String;

macro_rules! inline_test_strings {
    () => ((0u8..16u8).map(|i| (0u8..i).map(|j| (j  + 'a' as u8) as char).collect::<String>()));
}

#[test]
fn inline_as_slice() {
    for ref s in inline_test_strings!() {
        let sym = Inline::new(&s.as_ref());
        assert_eq!(sym.as_ref(), AsRef::<str>::as_ref(s));
    }
}

#[test]
fn inline_packed_as_slice() {
    for ref s in inline_test_strings!() {
        let inl = Inline::new(s.as_ref());
        assert_eq!(inl.as_ref(), AsRef::<str>::as_ref(s));
        assert_eq!(inl.pack().as_ref(), AsRef::<str>::as_ref(s));
    }
}

#[test]
fn inline_pack_unpack() {
    let foo = Inline::new("foo");
    assert_eq!(foo.as_ref(), "foo");

    let bar = foo.pack();

    println!("{:?}", foo);
    println!("{:?}", bar);

    panic_unless!(foo == foo, "each symbol::Inline instance should be equal to itself");
    panic_unless!(bar == bar, "each symbol::Symbol instance should be equal to itself");

    panic_unless!(Unpacked::Inline(foo) == bar.unpack(),
                  "pack-unpack cycle on a symbol::Inline should yield the same symbol");
}

#[test]
fn pooled_pack_unpack() {
    let mut pool = Pool::new();
    let a_str = "it was a very nice day";
    let b_str = "and everyone was happy";

    let a = pool.symbol(a_str);
    let b = pool.symbol(b_str);
    assert_eq!(a.type_of(), Type::POOLED);
    assert_eq!(b.type_of(), Type::POOLED);

   println!("{:?} => {:?}", a, a.as_ref());
    println!("{:?}", a.unpack());

    assert_eq!(a, a);
    panic_unless!(a != b && b != a, "`a` and `b` are distinct symbols and should not be equal");
    assert_eq!(a.as_ref(), a_str);
    assert_eq!(b.as_ref(), b_str);
}
<commit_msg>test/test_symbol.rs: fix missing space in a line's indent<commit_after>use std::convert::AsRef;
use cripes::symbol::{Pool,Type,Unpacked,Inline,PackFormat};
use std::string::String;

macro_rules! inline_test_strings {
    () => ((0u8..16u8).map(|i| (0u8..i).map(|j| (j  + 'a' as u8) as char).collect::<String>()));
}

#[test]
fn inline_as_slice() {
    for ref s in inline_test_strings!() {
        let sym = Inline::new(&s.as_ref());
        assert_eq!(sym.as_ref(), AsRef::<str>::as_ref(s));
    }
}

#[test]
fn inline_packed_as_slice() {
    for ref s in inline_test_strings!() {
        let inl = Inline::new(s.as_ref());
        assert_eq!(inl.as_ref(), AsRef::<str>::as_ref(s));
        assert_eq!(inl.pack().as_ref(), AsRef::<str>::as_ref(s));
    }
}

#[test]
fn inline_pack_unpack() {
    let foo = Inline::new("foo");
    assert_eq!(foo.as_ref(), "foo");

    let bar = foo.pack();

    println!("{:?}", foo);
    println!("{:?}", bar);

    panic_unless!(foo == foo, "each symbol::Inline instance should be equal to itself");
    panic_unless!(bar == bar, "each symbol::Symbol instance should be equal to itself");

    panic_unless!(Unpacked::Inline(foo) == bar.unpack(),
                  "pack-unpack cycle on a symbol::Inline should yield the same symbol");
}

#[test]
fn pooled_pack_unpack() {
    let mut pool = Pool::new();
    let a_str = "it was a very nice day";
    let b_str = "and everyone was happy";

    let a = pool.symbol(a_str);
    let b = pool.symbol(b_str);
    assert_eq!(a.type_of(), Type::POOLED);
    assert_eq!(b.type_of(), Type::POOLED);

    println!("{:?} => {:?}", a, a.as_ref());
    println!("{:?}", a.unpack());

    assert_eq!(a, a);
    panic_unless!(a != b && b != a, "`a` and `b` are distinct symbols and should not be equal");
    assert_eq!(a.as_ref(), a_str);
    assert_eq!(b.as_ref(), b_str);
}
<|endoftext|>


<commit_before>use byteorder::{LittleEndian, WriteBytesExt};
use std::collections::HashSet;
use std::io::prelude::*;
use std::io::{Cursor, Seek};
use std::iter::FromIterator;
use zip::write::FileOptions;
use zip::{CompressionMethod, SUPPORTED_METHODS};

// This test asserts that after creating a zip file, then reading its contents back out,
// the extracted data will *always* be exactly the same as the original data.
#[test]
fn end_to_end() {
    for &method in SUPPORTED_METHODS {
        let file = &mut Cursor::new(Vec::new());

        println!("Writing file with {} compression", method);
        write_to_zip(file, method).expect("Couldn't write to test file");

        println!("Checking file contents");
        check_zip_contents(file, ENTRY_NAME, Some(method));
    }
}

// This test asserts that after copying a `ZipFile` to a new `ZipWriter`, then reading its
// contents back out, the extracted data will *always* be exactly the same as the original data.
#[test]
fn copy() {
    for &method in SUPPORTED_METHODS {
        let src_file = &mut Cursor::new(Vec::new());
        write_to_zip(src_file, method).expect("Couldn't write to test file");

        let mut tgt_file = &mut Cursor::new(Vec::new());

        {
            let mut src_archive = zip::ZipArchive::new(src_file).unwrap();
            let mut zip = zip::ZipWriter::new(&mut tgt_file);

            {
                let file = src_archive
                    .by_name(ENTRY_NAME)
                    .expect("Missing expected file");

                zip.raw_copy_file(file).expect("Couldn't copy file");
            }

            {
                let file = src_archive
                    .by_name(ENTRY_NAME)
                    .expect("Missing expected file");

                zip.raw_copy_file_rename(file, COPY_ENTRY_NAME)
                    .expect("Couldn't copy and rename file");
            }
        }

        let mut tgt_archive = zip::ZipArchive::new(tgt_file).unwrap();

        check_zip_file_contents(&mut tgt_archive, ENTRY_NAME);
        check_zip_file_contents(&mut tgt_archive, COPY_ENTRY_NAME);
    }
}

// This test asserts that after appending to a `ZipWriter`, then reading its contents back out,
// both the prior data and the appended data will be exactly the same as their originals.
#[test]
fn append() {
    for &method in SUPPORTED_METHODS {
        let mut file = &mut Cursor::new(Vec::new());
        write_to_zip(file, method).expect("Couldn't write to test file");

        {
            let mut zip = zip::ZipWriter::new_append(&mut file).unwrap();
            zip.start_file(
                COPY_ENTRY_NAME,
                FileOptions::default().compression_method(method),
            )
            .unwrap();
            zip.write_all(LOREM_IPSUM).unwrap();
            zip.finish().unwrap();
        }

        let mut zip = zip::ZipArchive::new(&mut file).unwrap();
        check_zip_file_contents(&mut zip, ENTRY_NAME);
        check_zip_file_contents(&mut zip, COPY_ENTRY_NAME);
    }
}

// Write a test zip archive to buffer.
fn write_to_zip(
    file: &mut Cursor<Vec<u8>>,
    method: CompressionMethod,
) -> zip::result::ZipResult<()> {
    let mut zip = zip::ZipWriter::new(file);

    zip.add_directory("test/", Default::default())?;

    let options = FileOptions::default()
        .compression_method(method)
        .unix_permissions(0o755);

    zip.start_file("test/☃.txt", options)?;
    zip.write_all(b"Hello, World!\n")?;

    zip.start_file_with_extra_data("test_with_extra_data/🐢.txt", options)?;
    zip.write_u16::<LittleEndian>(0xbeef)?;
    zip.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
    zip.write_all(EXTRA_DATA)?;
    zip.end_extra_data()?;
    zip.write_all(b"Hello, World! Again.\n")?;

    zip.start_file(ENTRY_NAME, options)?;
    zip.write_all(LOREM_IPSUM)?;

    zip.finish()?;
    Ok(())
}

// Load an archive from buffer and check for expected test data.
fn read_zip<R: Read + Seek>(zip_file: R) -> zip::result::ZipResult<zip::ZipArchive<R>> {
    let mut archive = zip::ZipArchive::new(zip_file).unwrap();

    let expected_file_names = [
        "test/",
        "test/☃.txt",
        "test_with_extra_data/🐢.txt",
        ENTRY_NAME,
    ];
    let expected_file_names = HashSet::from_iter(expected_file_names.iter().copied());
    let file_names = archive.file_names().collect::<HashSet<_>>();
    assert_eq!(file_names, expected_file_names);

    {
        let file_with_extra_data = archive.by_name("test_with_extra_data/🐢.txt")?;
        let mut extra_data = Vec::new();
        extra_data.write_u16::<LittleEndian>(0xbeef)?;
        extra_data.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
        extra_data.write_all(EXTRA_DATA)?;
        assert_eq!(file_with_extra_data.extra_data(), extra_data.as_slice());
    }

    Ok(archive)
}

// Read a file in the archive as a string.
fn read_zip_file<R: Read + Seek>(
    archive: &mut zip::ZipArchive<R>,
    name: &str,
) -> zip::result::ZipResult<String> {
    let mut file = archive.by_name(name)?;

    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    Ok(contents)
}

// Check a file in the archive contains expected data.
fn check_zip_contents(
    zip_file: &mut Cursor<Vec<u8>>,
    name: &str,
    expected_method: Option<CompressionMethod>,
) {
    let mut archive = check_test_archive(zip_file).unwrap();

    if let Some(expected_method) = expected_method {
        // Check the file's compression method.
        let file = archive.by_name(name).unwrap();
        let real_method = file.compression();

        assert_eq!(
            expected_method, real_method,
            "File does not have expected compression method"
        );
    }

    check_test_file_contents(&mut archive, name);
}

// Check a file in the archive contains the lorem string.
fn check_test_file_contents<R: Read + Seek>(archive: &mut zip::ZipArchive<R>, name: &str) {
    let file_contents: String = read_zip_file(archive, name).unwrap();
    assert_eq!(file_contents.as_bytes(), LOREM_IPSUM);
}

const LOREM_IPSUM : &[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tellus elit, tristique vitae mattis egestas, ultricies vitae risus. Quisque sit amet quam ut urna aliquet
molestie. Proin blandit ornare dui, a tempor nisl accumsan in. Praesent a consequat felis. Morbi metus diam, auctor in auctor vel, feugiat id odio. Curabitur ex ex,
dictum quis auctor quis, suscipit id lorem. Aliquam vestibulum dolor nec enim vehicula, porta tristique augue tincidunt. Vivamus ut gravida est. Sed pellentesque, dolor
vitae tristique consectetur, neque lectus pulvinar dui, sed feugiat purus diam id lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
inceptos himenaeos. Maecenas feugiat velit in ex ultrices scelerisque id id neque.
";

const EXTRA_DATA: &[u8] = b"Extra Data";

const ENTRY_NAME: &str = "test/lorem_ipsum.txt";

const COPY_ENTRY_NAME: &str = "test/lorem_ipsum_renamed.txt";
<commit_msg>Update test helper function names<commit_after>use byteorder::{LittleEndian, WriteBytesExt};
use std::collections::HashSet;
use std::io::prelude::*;
use std::io::{Cursor, Seek};
use std::iter::FromIterator;
use zip::write::FileOptions;
use zip::{CompressionMethod, SUPPORTED_METHODS};

// This test asserts that after creating a zip file, then reading its contents back out,
// the extracted data will *always* be exactly the same as the original data.
#[test]
fn end_to_end() {
    for &method in SUPPORTED_METHODS {
        let file = &mut Cursor::new(Vec::new());

        println!("Writing file with {} compression", method);
        write_test_archive(file, method).expect("Couldn't write test zip archive");

        println!("Checking file contents");
        check_archive_file(file, ENTRY_NAME, Some(method));
    }
}

// This test asserts that after copying a `ZipFile` to a new `ZipWriter`, then reading its
// contents back out, the extracted data will *always* be exactly the same as the original data.
#[test]
fn copy() {
    for &method in SUPPORTED_METHODS {
        let src_file = &mut Cursor::new(Vec::new());
        write_test_archive(src_file, method).expect("Couldn't write to test file");

        let mut tgt_file = &mut Cursor::new(Vec::new());

        {
            let mut src_archive = zip::ZipArchive::new(src_file).unwrap();
            let mut zip = zip::ZipWriter::new(&mut tgt_file);

            {
                let file = src_archive
                    .by_name(ENTRY_NAME)
                    .expect("Missing expected file");

                zip.raw_copy_file(file).expect("Couldn't copy file");
            }

            {
                let file = src_archive
                    .by_name(ENTRY_NAME)
                    .expect("Missing expected file");

                zip.raw_copy_file_rename(file, COPY_ENTRY_NAME)
                    .expect("Couldn't copy and rename file");
            }
        }

        let mut tgt_archive = zip::ZipArchive::new(tgt_file).unwrap();

        check_test_file_contents(&mut tgt_archive, ENTRY_NAME);
        check_test_file_contents(&mut tgt_archive, COPY_ENTRY_NAME);
    }
}

// This test asserts that after appending to a `ZipWriter`, then reading its contents back out,
// both the prior data and the appended data will be exactly the same as their originals.
#[test]
fn append() {
    for &method in SUPPORTED_METHODS {
        let mut file = &mut Cursor::new(Vec::new());
        write_test_archive(file, method).expect("Couldn't write to test file");

        {
            let mut zip = zip::ZipWriter::new_append(&mut file).unwrap();
            zip.start_file(
                COPY_ENTRY_NAME,
                FileOptions::default().compression_method(method),
            )
            .unwrap();
            zip.write_all(LOREM_IPSUM).unwrap();
            zip.finish().unwrap();
        }

        let mut zip = zip::ZipArchive::new(&mut file).unwrap();
        check_test_file_contents(&mut zip, ENTRY_NAME);
        check_test_file_contents(&mut zip, COPY_ENTRY_NAME);
    }
}

// Write a test zip archive to buffer.
fn write_test_archive(
    file: &mut Cursor<Vec<u8>>,
    method: CompressionMethod,
) -> zip::result::ZipResult<()> {
    let mut zip = zip::ZipWriter::new(file);

    zip.add_directory("test/", Default::default())?;

    let options = FileOptions::default()
        .compression_method(method)
        .unix_permissions(0o755);

    zip.start_file("test/☃.txt", options)?;
    zip.write_all(b"Hello, World!\n")?;

    zip.start_file_with_extra_data("test_with_extra_data/🐢.txt", options)?;
    zip.write_u16::<LittleEndian>(0xbeef)?;
    zip.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
    zip.write_all(EXTRA_DATA)?;
    zip.end_extra_data()?;
    zip.write_all(b"Hello, World! Again.\n")?;

    zip.start_file(ENTRY_NAME, options)?;
    zip.write_all(LOREM_IPSUM)?;

    zip.finish()?;
    Ok(())
}

// Load an archive from buffer and check for test data.
fn check_test_archive<R: Read + Seek>(zip_file: R) -> zip::result::ZipResult<zip::ZipArchive<R>> {
    let mut archive = zip::ZipArchive::new(zip_file).unwrap();

    // Check archive contains expected files names.
    {
        let expected_file_names = [
            "test/",
            "test/☃.txt",
            "test_with_extra_data/🐢.txt",
            ENTRY_NAME,
        ];
        let expected_file_names = HashSet::from_iter(expected_file_names.iter().copied());
        let file_names = archive.file_names().collect::<HashSet<_>>();
        assert_eq!(file_names, expected_file_names);
    }

    // Check an archive file has expected extra field contents.
    {
        let file_with_extra_data = archive.by_name("test_with_extra_data/🐢.txt")?;
        let mut extra_data = Vec::new();
        extra_data.write_u16::<LittleEndian>(0xbeef)?;
        extra_data.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
        extra_data.write_all(EXTRA_DATA)?;
        assert_eq!(file_with_extra_data.extra_data(), extra_data.as_slice());
    }

    Ok(archive)
}

// Read a file in the archive as a string.
fn read_archive_file<R: Read + Seek>(
    archive: &mut zip::ZipArchive<R>,
    name: &str,
) -> zip::result::ZipResult<String> {
    let mut file = archive.by_name(name)?;

    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();

    Ok(contents)
}

// Check a file in the archive contains expected data.
fn check_archive_file(
    zip_file: &mut Cursor<Vec<u8>>,
    name: &str,
    expected_method: Option<CompressionMethod>,
) {
    let mut archive = check_test_archive(zip_file).unwrap();

    if let Some(expected_method) = expected_method {
        // Check the file's compression method.
        let file = archive.by_name(name).unwrap();
        let real_method = file.compression();

        assert_eq!(
            expected_method, real_method,
            "File does not have expected compression method"
        );
    }

    check_test_file_contents(&mut archive, name);
}

// Check a file in the archive contains the lorem string.
fn check_test_file_contents<R: Read + Seek>(archive: &mut zip::ZipArchive<R>, name: &str) {
    let file_contents: String = read_archive_file(archive, name).unwrap();
    assert_eq!(file_contents.as_bytes(), LOREM_IPSUM);
}

const LOREM_IPSUM : &[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tellus elit, tristique vitae mattis egestas, ultricies vitae risus. Quisque sit amet quam ut urna aliquet
molestie. Proin blandit ornare dui, a tempor nisl accumsan in. Praesent a consequat felis. Morbi metus diam, auctor in auctor vel, feugiat id odio. Curabitur ex ex,
dictum quis auctor quis, suscipit id lorem. Aliquam vestibulum dolor nec enim vehicula, porta tristique augue tincidunt. Vivamus ut gravida est. Sed pellentesque, dolor
vitae tristique consectetur, neque lectus pulvinar dui, sed feugiat purus diam id lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
inceptos himenaeos. Maecenas feugiat velit in ex ultrices scelerisque id id neque.
";

const EXTRA_DATA: &[u8] = b"Extra Data";

const ENTRY_NAME: &str = "test/lorem_ipsum.txt";

const COPY_ENTRY_NAME: &str = "test/lorem_ipsum_renamed.txt";
<|endoftext|>


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

use config;
use config::parameter_matchable::ParameterMatchable;
use env::Env;
use library;
use nameutil;
use super::conversion_type::ConversionType;
use super::rust_type::rust_type;
use super::ref_mode::RefMode;
use super::out_parameters::can_as_return;
use traits::IntoString;

//TODO: remove unused fields
#[derive(Clone, Debug)]
pub struct RustParameter {
    pub ind_c: usize, //index in `Vec<CParameter>`
    pub name: String,
    pub typ: library::TypeId,
    pub allow_none: bool,
}

#[derive(Clone, Debug)]
pub struct CParameter {
    pub name: String,
    pub typ: library::TypeId,
    pub c_type: String,
    pub instance_parameter: bool,
    pub direction: library::ParameterDirection,
    pub nullable: library::Nullable,
    pub transfer: library::Transfer,
    pub caller_allocates: bool,
    pub is_error: bool,

    //analysis fields
    pub ref_mode: RefMode,
}

#[derive(Clone, Debug)]
pub enum TransformationType {
    ToGlibDirect { name: String },
    ToGlibScalar {
        name: String,
        nullable: library::Nullable,
    },
    ToGlibPointer {
        name: String,
        instance_parameter: bool,
        transfer: library::Transfer,
        ref_mode: RefMode,
        //filled by functions
        to_glib_extra: String,
    },
    ToGlibStash { name: String },
    ToGlibBorrow,
    ToGlibUnknown { name: String },
    Into { name: String, with_stash: bool },
    Length {
        array_name: String,
        array_length_name: String,
        array_length_type: String,
    },
}

impl TransformationType {
    pub fn is_to_glib(&self) -> bool {
        use self::TransformationType::*;
        match *self {
            ToGlibDirect { .. } |
            ToGlibScalar { .. } |
            ToGlibPointer { .. } |
            ToGlibStash { .. } |
            ToGlibBorrow |
            ToGlibUnknown { .. } => true,
            _ => false,
        }
    }

    pub fn set_to_glib_extra(&mut self, to_glib_extra_: &str) {
        if let TransformationType::ToGlibPointer {
            ref mut to_glib_extra,
            ..
        } = *self
        {
            *to_glib_extra = to_glib_extra_.to_owned();
        }
    }
}

#[derive(Clone, Debug)]
pub struct Transformation {
    pub ind_c: usize,            //index in `Vec<CParameter>`
    pub ind_rust: Option<usize>, //index in `Vec<RustParameter>`
    pub transformation_type: TransformationType,
}

#[derive(Clone, Default, Debug)]
pub struct Parameters {
    pub rust_parameters: Vec<RustParameter>,
    pub c_parameters: Vec<CParameter>,
    pub transformations: Vec<Transformation>,
}

impl Parameters {
    fn new(capacity: usize) -> Parameters {
        Parameters {
            rust_parameters: Vec::with_capacity(capacity),
            c_parameters: Vec::with_capacity(capacity),
            transformations: Vec::with_capacity(capacity),
        }
    }

    pub fn analyze_return(&mut self, env: &Env, ret: &Option<library::Parameter>) {
        let array_length = if let Some(array_length) = ret.as_ref().and_then(|r| r.array_length) {
            array_length
        } else {
            return;
        };

        let ind_c = array_length as usize;

        let par = if let Some(par) = self.c_parameters.get(ind_c) {
            par
        } else {
            return;
        };

        let transformation = Transformation {
            ind_c: ind_c,
            ind_rust: None,
            transformation_type: get_length_type(env, "", &par.name, par.typ),
        };
        self.transformations.push(transformation);
    }
}

pub fn analyze(
    env: &Env,
    function_parameters: &[library::Parameter],
    configured_functions: &[&config::functions::Function],
) -> Parameters {
    let mut parameters = Parameters::new(function_parameters.len());

    //Map: length agrument position => array name
    let array_lengths: HashMap<u32, String> = function_parameters
        .iter()
        .filter_map(|p| p.array_length.map(|pos| (pos, p.name.clone())))
        .collect();

    for (pos, par) in function_parameters.iter().enumerate() {
        let name = if par.instance_parameter {
            par.name.clone()
        } else {
            nameutil::mangle_keywords(&*par.name).into_owned()
        };

        let ind_c = parameters.c_parameters.len();
        let mut ind_rust = Some(parameters.rust_parameters.len());

        let mut add_rust_parameter = match par.direction {
            library::ParameterDirection::In | library::ParameterDirection::InOut => true,
            library::ParameterDirection::Return => false,
            library::ParameterDirection::Out => !can_as_return(env, par),
        };

        let mut array_name = configured_functions
            .matched_parameters(&name)
            .iter()
            .filter_map(|p| p.length_of.as_ref())
            .next();
        if array_name.is_none() {
            array_name = array_lengths.get(&(pos as u32))
        }
        if let Some(array_name) = array_name {
            add_rust_parameter = false;

            let transformation = Transformation {
                ind_c: ind_c,
                ind_rust: None,
                transformation_type: get_length_type(env, array_name, &par.name, par.typ),
            };
            parameters.transformations.push(transformation);
        }

        let mut caller_allocates = par.caller_allocates;
        let mut transfer = par.transfer;
        let conversion = ConversionType::of(&env.library, par.typ);
        if conversion == ConversionType::Direct || conversion == ConversionType::Scalar {
            //For simply types no reason to have these flags
            caller_allocates = false;
            transfer = library::Transfer::None;
        }

        let immutable = configured_functions
            .matched_parameters(&name)
            .iter()
            .any(|p| p.constant);
        let ref_mode = RefMode::without_unneeded_mut(env, par, immutable);

        let nullable_override = configured_functions
            .matched_parameters(&name)
            .iter()
            .filter_map(|p| p.nullable)
            .next();
        let nullable = nullable_override.unwrap_or(par.nullable);

        let c_par = CParameter {
            name: name.clone(),
            typ: par.typ,
            c_type: par.c_type.clone(),
            instance_parameter: par.instance_parameter,
            direction: par.direction,
            transfer: transfer,
            caller_allocates: caller_allocates,
            nullable: nullable,
            ref_mode: ref_mode,
            is_error: par.is_error,
        };
        parameters.c_parameters.push(c_par);

        if add_rust_parameter {
            let rust_par = RustParameter {
                name: name.clone(),
                typ: par.typ,
                ind_c: ind_c,
                allow_none: par.allow_none,
            };
            parameters.rust_parameters.push(rust_par);

            if *nullable && is_into(env, par) {
                let with_stash = ref_mode == RefMode::ByRef;
                let transformation = Transformation {
                    ind_c: ind_c,
                    ind_rust: ind_rust,
                    transformation_type: TransformationType::Into {
                        name: name.clone(),
                        with_stash: with_stash,
                    },
                };
                parameters.transformations.push(transformation);

                if with_stash {
                    parameters.transformations.push(Transformation {
                        ind_c: ind_c,
                        ind_rust: ind_rust,
                        transformation_type: TransformationType::ToGlibStash { name: name },
                    });

                    continue;
                }
            }
        } else {
            ind_rust = None;
        }

        let transformation_type = match ConversionType::of(&env.library, par.typ) {
            ConversionType::Direct => TransformationType::ToGlibDirect { name: name },
            ConversionType::Scalar => TransformationType::ToGlibScalar {
                name: name,
                nullable: nullable,
            },
            ConversionType::Pointer => TransformationType::ToGlibPointer {
                name: name,
                instance_parameter: par.instance_parameter,
                transfer: transfer,
                ref_mode: ref_mode,
                to_glib_extra: String::new(),
            },
            ConversionType::Borrow => TransformationType::ToGlibBorrow,
            ConversionType::Unknown => TransformationType::ToGlibUnknown { name: name },
        };

        let transformation = Transformation {
            ind_c: ind_c,
            ind_rust: ind_rust,
            transformation_type: transformation_type,
        };
        parameters.transformations.push(transformation);
    }

    parameters
}

fn is_into(env: &Env, par: &library::Parameter) -> bool {
    fn is_into_inner(env: &Env, par: &library::Type) -> bool {
        match *par {
            library::Type::Fundamental(fund) => {
                match fund {
                    library::Fundamental::Utf8 | library::Fundamental::Type => true,
                    _ => false,
                }
            }
            library::Type::List(_) | library::Type::SList(_) | library::Type::CArray(_) => false,
            library::Type::Alias(ref alias) => is_into_inner(env, env.library.type_(alias.typ)),
            _ => true,
        }
    }
    !par.instance_parameter && is_into_inner(env, env.library.type_(par.typ))
}

fn get_length_type(
    env: &Env,
    array_name: &str,
    length_name: &str,
    length_typ: library::TypeId,
) -> TransformationType {
    let array_length_type = rust_type(env, length_typ).into_string();
    TransformationType::Length {
        array_name: array_name.to_string(),
        array_length_name: length_name.to_string(),
        array_length_type: array_length_type,
    }
}
<commit_msg>Add detection of length input parameters<commit_after>use std::collections::HashMap;

use config;
use config::parameter_matchable::ParameterMatchable;
use env::Env;
use library;
use nameutil;
use super::conversion_type::ConversionType;
use super::rust_type::rust_type;
use super::ref_mode::RefMode;
use super::out_parameters::can_as_return;
use traits::IntoString;

//TODO: remove unused fields
#[derive(Clone, Debug)]
pub struct RustParameter {
    pub ind_c: usize, //index in `Vec<CParameter>`
    pub name: String,
    pub typ: library::TypeId,
    pub allow_none: bool,
}

#[derive(Clone, Debug)]
pub struct CParameter {
    pub name: String,
    pub typ: library::TypeId,
    pub c_type: String,
    pub instance_parameter: bool,
    pub direction: library::ParameterDirection,
    pub nullable: library::Nullable,
    pub transfer: library::Transfer,
    pub caller_allocates: bool,
    pub is_error: bool,

    //analysis fields
    pub ref_mode: RefMode,
}

#[derive(Clone, Debug)]
pub enum TransformationType {
    ToGlibDirect { name: String },
    ToGlibScalar {
        name: String,
        nullable: library::Nullable,
    },
    ToGlibPointer {
        name: String,
        instance_parameter: bool,
        transfer: library::Transfer,
        ref_mode: RefMode,
        //filled by functions
        to_glib_extra: String,
    },
    ToGlibStash { name: String },
    ToGlibBorrow,
    ToGlibUnknown { name: String },
    Into { name: String, with_stash: bool },
    Length {
        array_name: String,
        array_length_name: String,
        array_length_type: String,
    },
}

impl TransformationType {
    pub fn is_to_glib(&self) -> bool {
        use self::TransformationType::*;
        match *self {
            ToGlibDirect { .. } |
            ToGlibScalar { .. } |
            ToGlibPointer { .. } |
            ToGlibStash { .. } |
            ToGlibBorrow |
            ToGlibUnknown { .. } => true,
            _ => false,
        }
    }

    pub fn set_to_glib_extra(&mut self, to_glib_extra_: &str) {
        if let TransformationType::ToGlibPointer {
            ref mut to_glib_extra,
            ..
        } = *self
        {
            *to_glib_extra = to_glib_extra_.to_owned();
        }
    }
}

#[derive(Clone, Debug)]
pub struct Transformation {
    pub ind_c: usize,            //index in `Vec<CParameter>`
    pub ind_rust: Option<usize>, //index in `Vec<RustParameter>`
    pub transformation_type: TransformationType,
}

#[derive(Clone, Default, Debug)]
pub struct Parameters {
    pub rust_parameters: Vec<RustParameter>,
    pub c_parameters: Vec<CParameter>,
    pub transformations: Vec<Transformation>,
}

impl Parameters {
    fn new(capacity: usize) -> Parameters {
        Parameters {
            rust_parameters: Vec::with_capacity(capacity),
            c_parameters: Vec::with_capacity(capacity),
            transformations: Vec::with_capacity(capacity),
        }
    }

    pub fn analyze_return(&mut self, env: &Env, ret: &Option<library::Parameter>) {
        let array_length = if let Some(array_length) = ret.as_ref().and_then(|r| r.array_length) {
            array_length
        } else {
            return;
        };

        let ind_c = array_length as usize;

        let par = if let Some(par) = self.c_parameters.get(ind_c) {
            par
        } else {
            return;
        };

        let transformation = Transformation {
            ind_c: ind_c,
            ind_rust: None,
            transformation_type: get_length_type(env, "", &par.name, par.typ),
        };
        self.transformations.push(transformation);
    }
}

pub fn analyze(
    env: &Env,
    function_parameters: &[library::Parameter],
    configured_functions: &[&config::functions::Function],
) -> Parameters {
    let mut parameters = Parameters::new(function_parameters.len());

    //Map: length agrument position => array name
    let array_lengths: HashMap<u32, String> = function_parameters
        .iter()
        .filter_map(|p| p.array_length.map(|pos| (pos, p.name.clone())))
        .collect();

    for (pos, par) in function_parameters.iter().enumerate() {
        let name = if par.instance_parameter {
            par.name.clone()
        } else {
            nameutil::mangle_keywords(&*par.name).into_owned()
        };

        let ind_c = parameters.c_parameters.len();
        let mut ind_rust = Some(parameters.rust_parameters.len());

        let mut add_rust_parameter = match par.direction {
            library::ParameterDirection::In | library::ParameterDirection::InOut => true,
            library::ParameterDirection::Return => false,
            library::ParameterDirection::Out => !can_as_return(env, par),
        };

        let mut array_name = configured_functions
            .matched_parameters(&name)
            .iter()
            .filter_map(|p| p.length_of.as_ref())
            .next();
        if array_name.is_none() {
            array_name = array_lengths.get(&(pos as u32))
        }
        if array_name.is_none() {
            array_name = detect_length(env, pos, par, function_parameters);
        }
        if let Some(array_name) = array_name {
            add_rust_parameter = false;

            let transformation = Transformation {
                ind_c: ind_c,
                ind_rust: None,
                transformation_type: get_length_type(env, array_name, &par.name, par.typ),
            };
            parameters.transformations.push(transformation);
        }

        let mut caller_allocates = par.caller_allocates;
        let mut transfer = par.transfer;
        let conversion = ConversionType::of(&env.library, par.typ);
        if conversion == ConversionType::Direct || conversion == ConversionType::Scalar {
            //For simply types no reason to have these flags
            caller_allocates = false;
            transfer = library::Transfer::None;
        }

        let immutable = configured_functions
            .matched_parameters(&name)
            .iter()
            .any(|p| p.constant);
        let ref_mode = RefMode::without_unneeded_mut(env, par, immutable);

        let nullable_override = configured_functions
            .matched_parameters(&name)
            .iter()
            .filter_map(|p| p.nullable)
            .next();
        let nullable = nullable_override.unwrap_or(par.nullable);

        let c_par = CParameter {
            name: name.clone(),
            typ: par.typ,
            c_type: par.c_type.clone(),
            instance_parameter: par.instance_parameter,
            direction: par.direction,
            transfer: transfer,
            caller_allocates: caller_allocates,
            nullable: nullable,
            ref_mode: ref_mode,
            is_error: par.is_error,
        };
        parameters.c_parameters.push(c_par);

        if add_rust_parameter {
            let rust_par = RustParameter {
                name: name.clone(),
                typ: par.typ,
                ind_c: ind_c,
                allow_none: par.allow_none,
            };
            parameters.rust_parameters.push(rust_par);

            if *nullable && is_into(env, par) {
                let with_stash = ref_mode == RefMode::ByRef;
                let transformation = Transformation {
                    ind_c: ind_c,
                    ind_rust: ind_rust,
                    transformation_type: TransformationType::Into {
                        name: name.clone(),
                        with_stash: with_stash,
                    },
                };
                parameters.transformations.push(transformation);

                if with_stash {
                    parameters.transformations.push(Transformation {
                        ind_c: ind_c,
                        ind_rust: ind_rust,
                        transformation_type: TransformationType::ToGlibStash { name: name },
                    });

                    continue;
                }
            }
        } else {
            ind_rust = None;
        }

        let transformation_type = match ConversionType::of(&env.library, par.typ) {
            ConversionType::Direct => TransformationType::ToGlibDirect { name: name },
            ConversionType::Scalar => TransformationType::ToGlibScalar {
                name: name,
                nullable: nullable,
            },
            ConversionType::Pointer => TransformationType::ToGlibPointer {
                name: name,
                instance_parameter: par.instance_parameter,
                transfer: transfer,
                ref_mode: ref_mode,
                to_glib_extra: String::new(),
            },
            ConversionType::Borrow => TransformationType::ToGlibBorrow,
            ConversionType::Unknown => TransformationType::ToGlibUnknown { name: name },
        };

        let transformation = Transformation {
            ind_c: ind_c,
            ind_rust: ind_rust,
            transformation_type: transformation_type,
        };
        parameters.transformations.push(transformation);
    }

    parameters
}

fn is_into(env: &Env, par: &library::Parameter) -> bool {
    fn is_into_inner(env: &Env, par: &library::Type) -> bool {
        match *par {
            library::Type::Fundamental(fund) => match fund {
                library::Fundamental::Utf8 | library::Fundamental::Type => true,
                _ => false,
            },
            library::Type::List(_) | library::Type::SList(_) | library::Type::CArray(_) => false,
            library::Type::Alias(ref alias) => is_into_inner(env, env.library.type_(alias.typ)),
            _ => true,
        }
    }
    !par.instance_parameter && is_into_inner(env, env.library.type_(par.typ))
}

fn get_length_type(
    env: &Env,
    array_name: &str,
    length_name: &str,
    length_typ: library::TypeId,
) -> TransformationType {
    let array_length_type = rust_type(env, length_typ).into_string();
    TransformationType::Length {
        array_name: array_name.to_string(),
        array_length_name: length_name.to_string(),
        array_length_type: array_length_type,
    }
}

fn detect_length<'a>(
    env: &Env,
    pos: usize,
    par: &library::Parameter,
    parameters: &'a [library::Parameter],
) -> Option<&'a String> {
    if !is_length(par) {
        return None;
    }

    let array = parameters.get(pos - 1).and_then(
        |p| if has_length(env, p.typ) {
            Some(p)
        } else {
            None
        },
    );
    array.map(|p| &p.name)
}

fn is_length(par: &library::Parameter) -> bool {
    if par.direction != library::ParameterDirection::In {
        return false;
    }

    if par.name.len() >= 3 && &par.name[0..3] == "len" {
        return true;
    }
    if par.name.find("length").is_some() {
        return true;
    }

    false
}

fn has_length(env: &Env, typ: library::TypeId) -> bool {
    use library::Type;
    let typ = env.library.type_(typ);
    match *typ {
        Type::Fundamental(fund) => {
            use library::Fundamental::*;
            match fund {
                Utf8 => true,
                Filename => true,
                _ => false,
            }
        }
        Type::CArray(..) |
        Type::FixedArray(..) |
        Type::Array(..) |
        Type::PtrArray(..) |
        Type::List(..) |
        Type::SList(..) |
        Type::HashTable(..) => true,
        Type::Alias(ref alias) => has_length(env, alias.typ),
        _ => false,
    }
}
<|endoftext|>


<commit_before>use gfx;
use gfx_phase;
use gfx_phase::Object;
use gfx_scene;
use std::cmp::Ordering;

pub fn order<S: PartialOrd, R: gfx::Resources>(
             a: &Object<S, super::Kernel, super::Params<R>>,
             b: &Object<S, super::Kernel, super::Params<R>>)
             -> Ordering {
    match (a.kernel, b.kernel) {
        (None, None)        => Object::front_to_back(a, b),
        (None, Some(_))     => Ordering::Less,
        (Some(_), None)     => Ordering::Greater,
        (Some(_), Some(_))  => Object::back_to_front(a, b),
    }
}

pub struct Pipeline<D: gfx::Device> {
    pub phase: super::Phase<D::Resources>,
    pub renderer: gfx::Renderer<D::Resources, D::CommandBuffer>,
    pub background: Option<gfx::ColorValue>,
}

impl<D: gfx::Device> Pipeline<D> {
    pub fn new<F: gfx::Factory<D::Resources>>(factory: &mut F,
               tex_default: gfx::shade::TextureParam<D::Resources>)
               -> Result<Pipeline<D>, gfx::ProgramError> {
        use gfx::traits::RenderFactory;
        let renderer = factory.create_renderer();
        super::Technique::new(factory, tex_default).map(|tech| Pipeline {
            phase: gfx_phase::Phase::new_cached("Main", tech),
            renderer: renderer,
            background: Some([0.0; 4]),
        })
    }
}

impl<D: gfx::Device> ::Pipeline<f32, D> for Pipeline<D> {
    fn render<
        C: gfx_scene::OrderedScene<D::Resources, ViewInfo = ::view::Info<f32>>,
        O: gfx::Output<D::Resources>,
    >(  &mut self, scene: &C, camera: &C::Camera, output: &O)
        -> Result<gfx::SubmitInfo<D>, gfx_scene::Error>
    where
        C::Entity: gfx_phase::Entity<D::Resources, ::Material<D::Resources>>,
    {
        self.renderer.reset();
        // clear
        match self.background {
            Some(color) => {
                let cdata = gfx::ClearData {
                    color: color,
                    depth: 1.0,
                    stencil: 0,
                };
                self.renderer.clear(cdata, gfx::COLOR | gfx::DEPTH, output);
            },
            None => (),
        }
        // draw
        match scene.draw_ordered(&mut self.phase, order, camera, output, &mut self.renderer)  {
            Ok(_) => Ok(self.renderer.as_buffer()),
            Err(e) => Err(e),
        }
    }
}
<commit_msg>Added a dummy Device parameter to Forward constructor<commit_after>use gfx;
use gfx_phase;
use gfx_phase::Object;
use gfx_scene;
use std::cmp::Ordering;

pub fn order<S: PartialOrd, R: gfx::Resources>(
             a: &Object<S, super::Kernel, super::Params<R>>,
             b: &Object<S, super::Kernel, super::Params<R>>)
             -> Ordering {
    match (a.kernel, b.kernel) {
        (None, None)        => Object::front_to_back(a, b),
        (None, Some(_))     => Ordering::Less,
        (Some(_), None)     => Ordering::Greater,
        (Some(_), Some(_))  => Object::back_to_front(a, b),
    }
}

pub struct Pipeline<D: gfx::Device> {
    pub phase: super::Phase<D::Resources>,
    pub renderer: gfx::Renderer<D::Resources, D::CommandBuffer>,
    pub background: Option<gfx::ColorValue>,
}

impl<D: gfx::Device> Pipeline<D> {
    pub fn new<F: gfx::Factory<D::Resources>>(_: &D, factory: &mut F,
               tex_default: gfx::shade::TextureParam<D::Resources>)
               -> Result<Pipeline<D>, gfx::ProgramError> {
        use gfx::traits::RenderFactory;
        let renderer = factory.create_renderer();
        super::Technique::new(factory, tex_default).map(|tech| Pipeline {
            phase: gfx_phase::Phase::new_cached("Main", tech),
            renderer: renderer,
            background: Some([0.0; 4]),
        })
    }
}

impl<D: gfx::Device> ::Pipeline<f32, D> for Pipeline<D> {
    fn render<
        C: gfx_scene::OrderedScene<D::Resources, ViewInfo = ::view::Info<f32>>,
        O: gfx::Output<D::Resources>,
    >(  &mut self, scene: &C, camera: &C::Camera, output: &O)
        -> Result<gfx::SubmitInfo<D>, gfx_scene::Error>
    where
        C::Entity: gfx_phase::Entity<D::Resources, ::Material<D::Resources>>,
    {
        self.renderer.reset();
        // clear
        match self.background {
            Some(color) => {
                let cdata = gfx::ClearData {
                    color: color,
                    depth: 1.0,
                    stencil: 0,
                };
                self.renderer.clear(cdata, gfx::COLOR | gfx::DEPTH, output);
            },
            None => (),
        }
        // draw
        match scene.draw_ordered(&mut self.phase, order, camera, output, &mut self.renderer)  {
            Ok(_) => Ok(self.renderer.as_buffer()),
            Err(e) => Err(e),
        }
    }
}
<|endoftext|>


<commit_before>use nom::{
  be_u8, be_u16,
  IResult,
  ErrorCode, Err,
};

use frame::{
  ChannelAssignment, NumberType,
  Frame,
  Header, Footer,
};

use metadata::StreamInfo;
use utility::{crc8, crc16, to_u32};

pub fn frame_parser<'a>(input: &'a [u8], stream_info: &StreamInfo)
                        -> IResult<'a, &'a [u8], Frame> {
  let result = chain!(input,
    frame_header: apply!(header, stream_info) ~
    frame_footer: footer,
    || {
      Frame {
        header: frame_header,
        footer: frame_footer,
      }
    }
  );

  match result {
    IResult::Done(i, frame)   => {
      // All frame bytes before the crc-16
      let end         = (input.len() - i.len()) - 2;
      let Footer(crc) = frame.footer;

      if crc16(&input[0..end]) == crc {
        IResult::Done(i, frame)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn blocking_strategy(input: &[u8]) -> IResult<&[u8], bool> {
  match take!(input, 2) {
    IResult::Done(i, bytes)   => {
      let sync_code = ((bytes[0] as u16) << 6) +
                      ((bytes[1] as u16) >> 2);
      let is_valid  = ((bytes[1] >> 1) & 0b01) == 0;

      if sync_code == 0b11111111111110 && is_valid {
        let is_variable_block_size = (bytes[1] & 0b01) == 1;

        IResult::Done(i, is_variable_block_size)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn block_sample(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
  match be_u8(input) {
    IResult::Done(i, byte)    => {
      let block_byte  = byte >> 4;
      let sample_byte = byte & 0x0f;
      let is_valid    = block_byte != 0b0000 && sample_byte != 0b1111;

      if is_valid {
        IResult::Done(i, (block_byte, sample_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn channel_bits(input: &[u8]) -> IResult<&[u8], (ChannelAssignment, u8)> {
  match be_u8(input) {
    IResult::Done(i, byte)    => {
      let channel_byte       = byte >> 4;
      let channel_assignment = match channel_byte {
        0b0000...0b0111 => ChannelAssignment::Independent,
        0b1000          => ChannelAssignment::LeftSide,
        0b1001          => ChannelAssignment::RightSide,
        0b1010          => ChannelAssignment::MiddleSide,
        _               => ChannelAssignment::Independent,
      };
      let size_byte = (byte >> 1) & 0b0111;

      // Checks the validity of:
      //
      // * (4 bits) channel assignment
      // * (3 bits) sample size
      // * (1 bit) last bit
      //
      // All these checks are whether of not they are reserved and should
      // return an error if so.
      let is_valid = channel_byte < 0b1011 &&
                     (size_byte != 0b0011 && size_byte != 0b0111) &&
                     (byte & 0b01) == 0;

      if is_valid {
        IResult::Done(i, (channel_assignment, size_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn utf8_size(input: &[u8], is_u64: bool)
             -> IResult<&[u8], Option<(usize, u8)>> {
  map!(input, be_u8, |utf8_header| {
    match utf8_header {
      0b00000000...0b01111111 => Some((0, utf8_header)),
      0b11000000...0b11011111 => Some((1, utf8_header & 0b00011111)),
      0b11100000...0b11101111 => Some((2, utf8_header & 0b00001111)),
      0b11110000...0b11110111 => Some((3, utf8_header & 0b00000111)),
      0b11111000...0b11111011 => Some((4, utf8_header & 0b00000011)),
      0b11111100...0b11111101 => Some((5, utf8_header & 0b00000001)),
      0b11111110              => if is_u64 { Some((6, 0)) } else { None },
      _                       => None,
    }
  })
}

fn number_type(input: &[u8], is_sample: bool,
               (size, value): (usize, u8))
               -> IResult<&[u8], NumberType> {
  let mut result   = value as u64;
  let mut is_error = false;

  match take!(input, size) {
    IResult::Done(i, bytes)   => {
      for i in 0..size {
        let byte = bytes[i] as u64;

        if byte >= 0b10000000 && byte <= 0b10111111 {
          result = (result << 6) + (byte & 0b00111111);
        } else {
          is_error = true;
          break;
        }
      }

      if is_error {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      } else if is_sample {
        IResult::Done(i, NumberType::Sample(result))
      } else {
        IResult::Done(i, NumberType::Frame(result as u32))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn secondary_block_size(input: &[u8], block_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match block_byte {
    0b0110 => opt!(input, map!(take!(1), to_u32)),
    0b0111 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn secondary_sample_rate(input: &[u8], sample_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match sample_byte {
    0b1100 => opt!(input, map!(take!(1), to_u32)),
    0b1101 => opt!(input, map!(take!(2), to_u32)),
    0b1110 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

pub fn header<'a>(input: &'a [u8], stream_info: &StreamInfo)
                  -> IResult<'a, &'a [u8], Header> {
  let result = chain!(input,
    is_variable_block_size: blocking_strategy ~
    tuple0: block_sample ~
    tuple1: channel_bits ~
    number_opt: apply!(utf8_size, is_variable_block_size) ~
    number_length: expr_opt!(number_opt) ~
    number: apply!(number_type, is_variable_block_size, number_length) ~
    alt_block_size: apply!(secondary_block_size, tuple0.0) ~
    alt_sample_rate: apply!(secondary_sample_rate, tuple0.1) ~
    crc: be_u8,
    || {
      let (block_byte, sample_byte)       = tuple0;
      let (channel_assignment, size_byte) = tuple1;

      let block_size = match block_byte {
        0b0001          => 192,
        0b0010...0b0101 => 576 * 2_u32.pow(block_byte as u32 - 2),
        0b0110 | 0b0111 => alt_block_size.unwrap() + 1,
        0b1000...0b1111 => 256 * 2_u32.pow(block_byte as u32 - 8),
        _               => unreachable!(),
      };

      let sample_rate = match sample_byte {
        0b0000 => stream_info.sample_rate,
        0b0001 => 88200,
        0b0010 => 176400,
        0b0011 => 192000,
        0b0100 => 8000,
        0b0101 => 16000,
        0b0110 => 22050,
        0b0111 => 24000,
        0b1000 => 32000,
        0b1001 => 44100,
        0b1010 => 48000,
        0b1011 => 96000,
        0b1100 => alt_sample_rate.unwrap() * 1000,
        0b1101 => alt_sample_rate.unwrap(),
        0b1110 => alt_sample_rate.unwrap() * 10,
        _      => unreachable!(),
      };

      let bits_per_sample = match size_byte {
        0b0000 => stream_info.bits_per_sample as usize,
        0b0001 => 8,
        0b0010 => 12,
        0b0100 => 16,
        0b0101 => 20,
        0b0110 => 24,
        _      => unreachable!(),
      };

      Header {
        block_size: block_size,
        sample_rate: sample_rate,
        channel_assignment: channel_assignment,
        bits_per_sample: bits_per_sample,
        number: number,
        crc: crc,
      }
    }
  );

  match result {
    IResult::Done(i, frame_header) => {
      // All header bytes before the crc-8
      let end = (input.len() - i.len()) - 1;

      if crc8(&input[0..end]) == frame_header.crc {
        IResult::Done(i, frame_header)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)          => IResult::Error(error),
    IResult::Incomplete(need)      => IResult::Incomplete(need),
  }
}

named!(pub footer <&[u8], Footer>, map!(be_u16, Footer));

#[cfg(test)]
mod tests {
  use super::*;
  use frame::{
    Header, Footer,
    ChannelAssignment, NumberType,
  };
  use metadata::StreamInfo;
  use nom::IResult;

  #[test]
  fn test_header() {
    let input  = b"\xff\xf8\x53\x1c\xf0\x90\x80\x80\x2e";
    let info   = StreamInfo::new();
    let result = Header {
      block_size: 4608,
      sample_rate: 192000,
      channel_assignment: ChannelAssignment::Independent,
      bits_per_sample: 24,
      number: NumberType::Frame(65536),
      crc: 0x2e,
    };

    assert_eq!(header(input, &info), IResult::Done(&[][..], result));
  }

  #[test]
  fn test_footer() {
    let input  = b"\x03\xe8";
    let result = IResult::Done(&[][..], Footer(0x03e8));

    assert_eq!(footer(input), result);
  }
}
<commit_msg>Add secondary test for frame header parser<commit_after>use nom::{
  be_u8, be_u16,
  IResult,
  ErrorCode, Err,
};

use frame::{
  ChannelAssignment, NumberType,
  Frame,
  Header, Footer,
};

use metadata::StreamInfo;
use utility::{crc8, crc16, to_u32};

pub fn frame_parser<'a>(input: &'a [u8], stream_info: &StreamInfo)
                        -> IResult<'a, &'a [u8], Frame> {
  let result = chain!(input,
    frame_header: apply!(header, stream_info) ~
    frame_footer: footer,
    || {
      Frame {
        header: frame_header,
        footer: frame_footer,
      }
    }
  );

  match result {
    IResult::Done(i, frame)   => {
      // All frame bytes before the crc-16
      let end         = (input.len() - i.len()) - 2;
      let Footer(crc) = frame.footer;

      if crc16(&input[0..end]) == crc {
        IResult::Done(i, frame)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn blocking_strategy(input: &[u8]) -> IResult<&[u8], bool> {
  match take!(input, 2) {
    IResult::Done(i, bytes)   => {
      let sync_code = ((bytes[0] as u16) << 6) +
                      ((bytes[1] as u16) >> 2);
      let is_valid  = ((bytes[1] >> 1) & 0b01) == 0;

      if sync_code == 0b11111111111110 && is_valid {
        let is_variable_block_size = (bytes[1] & 0b01) == 1;

        IResult::Done(i, is_variable_block_size)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn block_sample(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
  match be_u8(input) {
    IResult::Done(i, byte)    => {
      let block_byte  = byte >> 4;
      let sample_byte = byte & 0x0f;
      let is_valid    = block_byte != 0b0000 && sample_byte != 0b1111;

      if is_valid {
        IResult::Done(i, (block_byte, sample_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn channel_bits(input: &[u8]) -> IResult<&[u8], (ChannelAssignment, u8)> {
  match be_u8(input) {
    IResult::Done(i, byte)    => {
      let channel_byte       = byte >> 4;
      let channel_assignment = match channel_byte {
        0b0000...0b0111 => ChannelAssignment::Independent,
        0b1000          => ChannelAssignment::LeftSide,
        0b1001          => ChannelAssignment::RightSide,
        0b1010          => ChannelAssignment::MiddleSide,
        _               => ChannelAssignment::Independent,
      };
      let size_byte = (byte >> 1) & 0b0111;

      // Checks the validity of:
      //
      // * (4 bits) channel assignment
      // * (3 bits) sample size
      // * (1 bit) last bit
      //
      // All these checks are whether of not they are reserved and should
      // return an error if so.
      let is_valid = channel_byte < 0b1011 &&
                     (size_byte != 0b0011 && size_byte != 0b0111) &&
                     (byte & 0b01) == 0;

      if is_valid {
        IResult::Done(i, (channel_assignment, size_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn utf8_size(input: &[u8], is_u64: bool)
             -> IResult<&[u8], Option<(usize, u8)>> {
  map!(input, be_u8, |utf8_header| {
    match utf8_header {
      0b00000000...0b01111111 => Some((0, utf8_header)),
      0b11000000...0b11011111 => Some((1, utf8_header & 0b00011111)),
      0b11100000...0b11101111 => Some((2, utf8_header & 0b00001111)),
      0b11110000...0b11110111 => Some((3, utf8_header & 0b00000111)),
      0b11111000...0b11111011 => Some((4, utf8_header & 0b00000011)),
      0b11111100...0b11111101 => Some((5, utf8_header & 0b00000001)),
      0b11111110              => if is_u64 { Some((6, 0)) } else { None },
      _                       => None,
    }
  })
}

fn number_type(input: &[u8], is_sample: bool,
               (size, value): (usize, u8))
               -> IResult<&[u8], NumberType> {
  let mut result   = value as u64;
  let mut is_error = false;

  match take!(input, size) {
    IResult::Done(i, bytes)   => {
      for i in 0..size {
        let byte = bytes[i] as u64;

        if byte >= 0b10000000 && byte <= 0b10111111 {
          result = (result << 6) + (byte & 0b00111111);
        } else {
          is_error = true;
          break;
        }
      }

      if is_error {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      } else if is_sample {
        IResult::Done(i, NumberType::Sample(result))
      } else {
        IResult::Done(i, NumberType::Frame(result as u32))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn secondary_block_size(input: &[u8], block_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match block_byte {
    0b0110 => opt!(input, map!(take!(1), to_u32)),
    0b0111 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn secondary_sample_rate(input: &[u8], sample_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match sample_byte {
    0b1100 => opt!(input, map!(take!(1), to_u32)),
    0b1101 => opt!(input, map!(take!(2), to_u32)),
    0b1110 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

pub fn header<'a>(input: &'a [u8], stream_info: &StreamInfo)
                  -> IResult<'a, &'a [u8], Header> {
  let result = chain!(input,
    is_variable_block_size: blocking_strategy ~
    tuple0: block_sample ~
    tuple1: channel_bits ~
    number_opt: apply!(utf8_size, is_variable_block_size) ~
    number_length: expr_opt!(number_opt) ~
    number: apply!(number_type, is_variable_block_size, number_length) ~
    alt_block_size: apply!(secondary_block_size, tuple0.0) ~
    alt_sample_rate: apply!(secondary_sample_rate, tuple0.1) ~
    crc: be_u8,
    || {
      let (block_byte, sample_byte)       = tuple0;
      let (channel_assignment, size_byte) = tuple1;

      let block_size = match block_byte {
        0b0001          => 192,
        0b0010...0b0101 => 576 * 2_u32.pow(block_byte as u32 - 2),
        0b0110 | 0b0111 => alt_block_size.unwrap() + 1,
        0b1000...0b1111 => 256 * 2_u32.pow(block_byte as u32 - 8),
        _               => unreachable!(),
      };

      let sample_rate = match sample_byte {
        0b0000 => stream_info.sample_rate,
        0b0001 => 88200,
        0b0010 => 176400,
        0b0011 => 192000,
        0b0100 => 8000,
        0b0101 => 16000,
        0b0110 => 22050,
        0b0111 => 24000,
        0b1000 => 32000,
        0b1001 => 44100,
        0b1010 => 48000,
        0b1011 => 96000,
        0b1100 => alt_sample_rate.unwrap() * 1000,
        0b1101 => alt_sample_rate.unwrap(),
        0b1110 => alt_sample_rate.unwrap() * 10,
        _      => unreachable!(),
      };

      let bits_per_sample = match size_byte {
        0b0000 => stream_info.bits_per_sample as usize,
        0b0001 => 8,
        0b0010 => 12,
        0b0100 => 16,
        0b0101 => 20,
        0b0110 => 24,
        _      => unreachable!(),
      };

      Header {
        block_size: block_size,
        sample_rate: sample_rate,
        channel_assignment: channel_assignment,
        bits_per_sample: bits_per_sample,
        number: number,
        crc: crc,
      }
    }
  );

  match result {
    IResult::Done(i, frame_header) => {
      // All header bytes before the crc-8
      let end = (input.len() - i.len()) - 1;

      if crc8(&input[0..end]) == frame_header.crc {
        IResult::Done(i, frame_header)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)          => IResult::Error(error),
    IResult::Incomplete(need)      => IResult::Incomplete(need),
  }
}

named!(pub footer <&[u8], Footer>, map!(be_u16, Footer));

#[cfg(test)]
mod tests {
  use super::*;
  use frame::{
    Header, Footer,
    ChannelAssignment, NumberType,
  };
  use metadata::StreamInfo;
  use nom::IResult;

  #[test]
  fn test_header() {
    let inputs   = [ &b"\xff\xf8\x53\x1c\xf0\x90\x80\x80\x2e"[..]
                   , &b"\xff\xf9\x7c\xa0\xfe\xbf\xbf\xbf\xbf\xbf\xbc\x01\xff\
                        \x01\x88"[..]
                   ];
    let mut info = StreamInfo::new();
    let results  = [ IResult::Done(&[][..], Header {
                      block_size: 4608,
                      sample_rate: 192000,
                      channel_assignment: ChannelAssignment::Independent,
                      bits_per_sample: 24,
                      number: NumberType::Frame(65536),
                      crc: 0x2e,
                    })
                  , IResult::Done(&[][..], Header {
                      block_size: 512,
                      sample_rate: 1000,
                      channel_assignment: ChannelAssignment::MiddleSide,
                      bits_per_sample: 16,
                      number: NumberType::Sample(68719476732),
                      crc: 0x88,
                    })
                  ];

    info.bits_per_sample = 16;

    assert_eq!(header(inputs[0], &info), results[0]);
    assert_eq!(header(inputs[1], &info), results[1]);
  }

  #[test]
  fn test_footer() {
    let input  = b"\x03\xe8";
    let result = IResult::Done(&[][..], Footer(0x03e8));

    assert_eq!(footer(input), result);
  }
}
<|endoftext|>


<commit_before>extern crate distrust;
extern crate memmap;

use distrust::buffer::*;
use distrust::proto::*;

use std::fs::File;
use std::fs::OpenOptions;
/*
use std::thread;
use std::sync::atomic::{AtomicIsize, Ordering};
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::mem;
use std::ptr;
use std::mem::transmute;
//use std::io::Write;
use std::error::Error;
*/
use std::error::Error;
use std::io::prelude::*;
use std::sync::atomic::Ordering;
use memmap::{Mmap, Protection};

#[test]
fn test_counter() {
    let mut f = File::create("/dev/shm/foo.txt").unwrap();
    let data: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0];
    match f.write_all(data) {
        Err(eh) => panic!("Failed to write: {}", Error::description(&eh)),
        Ok(_) => println!("Wrote data")
    }

    let file = OpenOptions::new().write(true).read(true).open("/dev/shm/foo.txt").unwrap();
    println!("Mapping....");
    let mut mem = match memmap::Mmap::open(&file, memmap::Protection::ReadWrite) {
        Err(reason) => panic!("Failed to map file: {}", reason),
        Ok(memFile) => memFile
    };

    let counter: MappedAtomicIsize = create_mapped_atomic(&mut mem, 0);
    println!("Mapped!");

    assert_eq!(0, counter.load(Ordering::Acquire));
    assert_eq!(0, counter.fetch_add(5, Ordering::AcqRel));

    assert_eq!(5, counter.load(Ordering::Acquire));

}

<commit_msg>threading test :(<commit_after>extern crate distrust;
extern crate memmap;

use distrust::buffer::*;
use distrust::proto::*;

use std::fs::File;
use std::fs::OpenOptions;
/*
use std::thread;
use std::sync::atomic::{AtomicIsize, Ordering};
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::mem;
use std::ptr;
use std::mem::transmute;
//use std::io::Write;
use std::error::Error;
*/
use std::thread;
use std::path::Path;
use std::error::Error;
use std::io::prelude::*;
use std::sync::atomic::Ordering;
use std::time::Duration;

use memmap::{Mmap, Protection};

#[test]
fn test_counter() {
    let mut f = File::create("/dev/shm/foo.txt").unwrap();
    let data: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0];
    match f.write_all(data) {
        Err(eh) => panic!("Failed to write: {}", Error::description(&eh)),
        Ok(_) => println!("Wrote data")
    }

    let file = OpenOptions::new().write(true).read(true).open("/dev/shm/foo.txt").unwrap();
    println!("Mapping....");
    let mut mem = match memmap::Mmap::open(&file, memmap::Protection::ReadWrite) {
        Err(reason) => panic!("Failed to map file: {}", reason),
        Ok(memFile) => memFile
    };

    let counter: MappedAtomicIsize = create_mapped_atomic(&mut mem, 0);
    println!("Mapped!");

    assert_eq!(0, counter.load(Ordering::Acquire));
    assert_eq!(0, counter.fetch_add(5, Ordering::AcqRel));

    assert_eq!(5, counter.load(Ordering::Acquire));

}

#[test]
fn test_discouraged_concurrent_access() {

    let h1 = thread::spawn(move || {
        let mut m1 = map_file(&Path::new("/dev/shm/map1.bin"));
        let c1 = create_mapped_atomic(&mut m1, 0);
        assert_eq!(0, c1.load(Ordering::Acquire));
        let mut previous = c1.load(Ordering::Acquire);
        for i in 0..10 {
            thread::sleep(Duration::from_millis(150));
            let current = c1.fetch_add(17, Ordering::AcqRel);
            if previous != current {
                println!("Oh noes! Concurrent modification observed by {:?}! Expected: {}, but was: {}", thread::current(), previous, current);
            }
            previous = current;
        }
    });
    let h2 = thread::spawn(move || {
        let mut m2 = map_file(&Path::new("/dev/shm/map1.bin"));
        let c2 = create_mapped_atomic(&mut m2, 0);
        let mut previous = c2.load(Ordering::Acquire);
        for i in 0..10 {
            thread::sleep(Duration::from_millis(150));
            let current = c2.fetch_add(17, Ordering::AcqRel);
            if previous != current {
                println!("Oh noes! Concurrent modification observed by {:?}! Expected: {}, but was: {}", thread::current(), previous, current);
            }
            previous = current;
        }
    });

    match h1.join() {
        Err(msg) => panic!("Join failed: {:?}", &msg),
        Ok(_) => println!("Join ok")
    }
    match h2.join() {
        Err(msg) => panic!("Join failed: {:?}", &msg),
        Ok(_) => println!("Join ok")
    }
}

fn map_file(path: &Path) -> memmap::Mmap {
    let mut f = File::create(path).unwrap();
    let data: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0];
    match f.write_all(data) {
        Err(eh) => panic!("Failed to write: {}", Error::description(&eh)),
        Ok(_) => println!("Wrote data")
    }

    let file = OpenOptions::new().write(true).read(true).open(path).unwrap();
    println!("Mapping....");
    let mut mem = match memmap::Mmap::open(&file, memmap::Protection::ReadWrite) {
        Err(reason) => panic!("Failed to map file: {}", reason),
        Ok(memFile) => memFile
    };

    mem
}
<|endoftext|>


<commit_before>use std::net::{TcpListener, SocketAddr};
use std::io::prelude::*;
use std::thread;
use std::sync::mpsc::{Sender, Receiver, channel};
use std::io::BufReader;

pub struct Server {
    messages: Option<Sender<Message>>,
    addr: SocketAddr,
    thread: Option<thread::JoinHandle<()>>,
}

enum Message {
    Read(String),
    Write(String),
}

fn run(listener: &TcpListener, rx: &Receiver<Message>) {
    let mut socket = BufReader::new(listener.accept().unwrap().0);
    for msg in rx.iter() {
        match msg {
            Message::Read(ref expected) => {
                let mut expected = &expected[..];
                while let Some(i) = expected.find("\n") {
                    let mut actual = String::new();
                    t!(socket.read_line(&mut actual));
                    assert_eq!(actual, &expected[..i + 1]);
                    expected = &expected[i + 1..];
                }
            }
            Message::Write(ref to_write) => {
                t!(socket.get_mut().write_all(to_write.as_bytes()));
                return
            }
        }
    }

    let mut dst = Vec::new();
    t!(socket.read_to_end(&mut dst));
    assert!(dst.len() == 0);
}

impl Server {
    pub fn new() -> Server {
        let listener = t!(TcpListener::bind("127.0.0.1:0"));
        let addr = t!(listener.local_addr());
        let (tx, rx) = channel();
        let thread = thread::spawn(move || run(&listener, &rx));
        Server {
            messages: Some(tx),
            addr: addr,
            thread: Some(thread),
        }
    }

    pub fn receive(&self, msg: &str) {
        let msg = msg.replace("$PORT", &self.addr.port().to_string());
        self.msg(Message::Read(msg));
    }

    pub fn send(&self, msg: &str) {
        let msg = msg.replace("$PORT", &self.addr.port().to_string());
        self.msg(Message::Write(msg));
    }

    fn msg(&self, msg: Message) {
        t!(self.messages.as_ref().unwrap().send(msg));
    }

    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }

    pub fn url(&self, path: &str) -> String {
        format!("http://{}{}", self.addr, path)
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        drop(self.messages.take());
        let res = self.thread.take().unwrap().join();
        if !thread::panicking() {
            t!(res);
        } else if let Err(e) = res {
            println!("child server thread also failed: {:?}", e);
        }
    }
}
<commit_msg>Work with headers out of order in tests<commit_after>use std::collections::HashSet;
use std::net::{TcpListener, SocketAddr};
use std::io::prelude::*;
use std::thread;
use std::sync::mpsc::{Sender, Receiver, channel};
use std::io::BufReader;

pub struct Server {
    messages: Option<Sender<Message>>,
    addr: SocketAddr,
    thread: Option<thread::JoinHandle<()>>,
}

enum Message {
    Read(String),
    Write(String),
}

fn run(listener: &TcpListener, rx: &Receiver<Message>) {
    let mut socket = BufReader::new(listener.accept().unwrap().0);
    for msg in rx.iter() {
        match msg {
            Message::Read(ref expected) => {
                let mut expected = &expected[..];
                let mut expected_headers = HashSet::new();
                while let Some(i) = expected.find("\n") {
                    let line = &expected[..i + 1];
                    expected = &expected[i + 1..];
                    if line == "\r" {
                        break
                    }
                    expected_headers.insert(line);
                }
                if expected.len() > 0 {
                    assert!(expected_headers.insert(expected));
                }

                while expected_headers.len() > 0 {
                    let mut actual = String::new();
                    t!(socket.read_line(&mut actual));
                    if !expected_headers.remove(&actual[..]) {
                        panic!("unexpected header: {:?}", actual);
                    }
                }
                for header in expected_headers {
                    panic!("expected header but not found: {:?}", header);
                }

                let mut buf = vec![0; expected.len()];
                if buf.len() > 0 {
                    t!(socket.read_exact(&mut buf));
                    assert_eq!(buf, expected.as_bytes());
                }
            }
            Message::Write(ref to_write) => {
                t!(socket.get_mut().write_all(to_write.as_bytes()));
                return
            }
        }
    }

    let mut dst = Vec::new();
    t!(socket.read_to_end(&mut dst));
    assert!(dst.len() == 0);
}

impl Server {
    pub fn new() -> Server {
        let listener = t!(TcpListener::bind("127.0.0.1:0"));
        let addr = t!(listener.local_addr());
        let (tx, rx) = channel();
        let thread = thread::spawn(move || run(&listener, &rx));
        Server {
            messages: Some(tx),
            addr: addr,
            thread: Some(thread),
        }
    }

    pub fn receive(&self, msg: &str) {
        let msg = msg.replace("$PORT", &self.addr.port().to_string());
        self.msg(Message::Read(msg));
    }

    pub fn send(&self, msg: &str) {
        let msg = msg.replace("$PORT", &self.addr.port().to_string());
        self.msg(Message::Write(msg));
    }

    fn msg(&self, msg: Message) {
        t!(self.messages.as_ref().unwrap().send(msg));
    }

    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }

    pub fn url(&self, path: &str) -> String {
        format!("http://{}{}", self.addr, path)
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        drop(self.messages.take());
        let res = self.thread.take().unwrap().join();
        if !thread::panicking() {
            t!(res);
        } else if let Err(e) = res {
            println!("child server thread also failed: {:?}", e);
        }
    }
}
<|endoftext|>