<commit_before>//! Compressed/slow/row-oriented storage for documents.
//!
//! A field needs to be marked as stored in the schema in
//! order to be handled in the `Store`.
//!
//! Internally, documents (or rather their stored fields) are serialized to a buffer.
//! When the buffer exceeds 16K, the buffer is compressed using `brotli`, `LZ4` or `snappy`
//! and the resulting block is written to disk.
//!
//! One can then request for a specific `DocId`.
//! A skip list helps navigating to the right block,
//! decompresses it entirely and returns the document within it.
//!
//! If the last document requested was in the same block,
//! the reader is smart enough to avoid decompressing
//! the block a second time, but their is no real
//! uncompressed block* cache.
//!
//! A typical use case for the store is, once
//! the search result page has been computed, returning
//! the actual content of the 10 best document.
//!
//! # Usage
//!
//! Most users should not access the `StoreReader` directly
//! and should rely on either
//!
//! - at the segment level, the
//! [`SegmentReader`'s `doc` method](../struct.SegmentReader.html#method.doc)
//! - at the index level, the
//! [`Searcher`'s `doc` method](../struct.Searcher.html#method.doc)
//!
//! !

mod compressors;
mod footer;
mod index;
mod reader;
mod writer;
pub use self::compressors::Compressor;
pub use self::reader::StoreReader;
pub use self::writer::StoreWriter;

#[cfg(feature = "lz4-compression")]
mod compression_lz4_block;

#[cfg(feature = "brotli-compression")]
mod compression_brotli;

#[cfg(feature = "snappy-compression")]
mod compression_snap;

#[cfg(test)]
pub mod tests {

    use std::path::Path;

    use futures::executor::block_on;

    use super::*;
    use crate::directory::{Directory, RamDirectory, WritePtr};
    use crate::fastfield::AliveBitSet;
    use crate::schema::{
        self, Document, FieldValue, Schema, TextFieldIndexing, TextOptions, STORED, TEXT,
    };
    use crate::{Index, Term};

    const LOREM: &str = "Doc Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \
                         eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad \
                         minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip \
                         ex ea commodo consequat. Duis aute irure dolor in reprehenderit in \
                         voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur \
                         sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt \
                         mollit anim id est laborum.";

    pub fn write_lorem_ipsum_store(
        writer: WritePtr,
        num_docs: usize,
        compressor: Compressor,
    ) -> Schema {
        let mut schema_builder = Schema::builder();
        let field_body = schema_builder.add_text_field("body", TextOptions::default().set_stored());
        let field_title =
            schema_builder.add_text_field("title", TextOptions::default().set_stored());
        let schema = schema_builder.build();
        {
            let mut store_writer = StoreWriter::new(writer, compressor);
            for i in 0..num_docs {
                let mut fields: Vec<FieldValue> = Vec::new();
                {
                    let field_value = FieldValue::new(field_body, From::from(LOREM.to_string()));
                    fields.push(field_value);
                }
                {
                    let title_text = format!("Doc {}", i);
                    let field_value = FieldValue::new(field_title, From::from(title_text));
                    fields.push(field_value);
                }
                // let fields_refs: Vec<&FieldValue> = fields.iter().collect();
                let doc = Document::from(fields);
                store_writer.store(&doc).unwrap();
            }
            store_writer.close().unwrap();
        }
        schema
    }

    const NUM_DOCS: usize = 1_000;
    #[test]
    fn test_doc_store_iter_with_delete_bug_1077() -> crate::Result<()> {
        // this will cover deletion of the first element in a checkpoint
        let deleted_doc_ids = (200..300).collect::<Vec<_>>();
        let alive_bitset =
            AliveBitSet::for_test_from_deleted_docs(&deleted_doc_ids, NUM_DOCS as u32);

        let path = Path::new("store");
        let directory = RamDirectory::create();
        let store_wrt = directory.open_write(path)?;
        let schema = write_lorem_ipsum_store(store_wrt, NUM_DOCS, Compressor::Lz4);
        let field_title = schema.get_field("title").unwrap();
        let store_file = directory.open_read(path)?;
        let store = StoreReader::open(store_file)?;
        for i in 0..NUM_DOCS as u32 {
            assert_eq!(
                *store
                    .get(i)?
                    .get_first(field_title)
                    .unwrap()
                    .as_text()
                    .unwrap(),
                format!("Doc {}", i)
            );
        }

        for (_, doc) in store.iter(Some(&alive_bitset)).enumerate() {
            let doc = doc?;
            let title_content = doc.get_first(field_title).unwrap().as_text().unwrap();
            if !title_content.starts_with("Doc ") {
                panic!("unexpected title_content {}", title_content);
            }

            let id = title_content
                .strip_prefix("Doc ")
                .unwrap()
                .parse::<u32>()
                .unwrap();
            if alive_bitset.is_deleted(id) {
                panic!("unexpected deleted document {}", id);
            }
        }

        Ok(())
    }

    fn test_store(compressor: Compressor) -> crate::Result<()> {
        let path = Path::new("store");
        let directory = RamDirectory::create();
        let store_wrt = directory.open_write(path)?;
        let schema = write_lorem_ipsum_store(store_wrt, NUM_DOCS, compressor);
        let field_title = schema.get_field("title").unwrap();
        let store_file = directory.open_read(path)?;
        let store = StoreReader::open(store_file)?;
        for i in 0..NUM_DOCS as u32 {
            assert_eq!(
                *store
                    .get(i)?
                    .get_first(field_title)
                    .unwrap()
                    .as_text()
                    .unwrap(),
                format!("Doc {}", i)
            );
        }
        for (i, doc) in store.iter(None).enumerate() {
            assert_eq!(
                *doc?.get_first(field_title).unwrap().as_text().unwrap(),
                format!("Doc {}", i)
            );
        }
        Ok(())
    }

    #[test]
    fn test_store_noop() -> crate::Result<()> {
        test_store(Compressor::None)
    }
    #[cfg(feature = "lz4-compression")]
    #[test]
    fn test_store_lz4_block() -> crate::Result<()> {
        test_store(Compressor::Lz4)
    }
    #[cfg(feature = "snappy-compression")]
    #[test]
    fn test_store_snap() -> crate::Result<()> {
        test_store(Compressor::Snappy)
    }
    #[cfg(feature = "brotli-compression")]
    #[test]
    fn test_store_brotli() -> crate::Result<()> {
        test_store(Compressor::Brotli)
    }

    #[test]
    fn test_store_with_delete() -> crate::Result<()> {
        let mut schema_builder = schema::Schema::builder();

        let text_field_options = TextOptions::default()
            .set_indexing_options(
                TextFieldIndexing::default()
                    .set_index_option(schema::IndexRecordOption::WithFreqsAndPositions),
            )
            .set_stored();
        let text_field = schema_builder.add_text_field("text_field", text_field_options);
        let schema = schema_builder.build();
        let index_builder = Index::builder().schema(schema);

        let index = index_builder.create_in_ram()?;

        {
            let mut index_writer = index.writer_for_tests().unwrap();
            index_writer.add_document(doc!(text_field=> "deleteme"))?;
            index_writer.add_document(doc!(text_field=> "deletemenot"))?;
            index_writer.add_document(doc!(text_field=> "deleteme"))?;
            index_writer.add_document(doc!(text_field=> "deletemenot"))?;
            index_writer.add_document(doc!(text_field=> "deleteme"))?;

            index_writer.delete_term(Term::from_field_text(text_field, "deleteme"));
            index_writer.commit()?;
        }

        let searcher = index.reader()?.searcher();
        let reader = searcher.segment_reader(0);
        let store = reader.get_store_reader()?;
        for doc in store.iter(reader.alive_bitset()) {
            assert_eq!(
                *doc?.get_first(text_field).unwrap().as_text().unwrap(),
                "deletemenot".to_string()
            );
        }
        Ok(())
    }

    #[cfg(feature = "snappy-compression")]
    #[cfg(feature = "lz4-compression")]
    #[test]
    fn test_merge_with_changed_compressor() -> crate::Result<()> {
        let mut schema_builder = schema::Schema::builder();

        let text_field = schema_builder.add_text_field("text_field", TEXT | STORED);
        let schema = schema_builder.build();
        let index_builder = Index::builder().schema(schema);

        let mut index = index_builder.create_in_ram().unwrap();
        index.settings_mut().docstore_compression = Compressor::Lz4;
        {
            let mut index_writer = index.writer_for_tests().unwrap();
            // put enough data create enough blocks in the doc store to be considered for stacking
            for _ in 0..200 {
                index_writer.add_document(doc!(text_field=> LOREM))?;
            }
            assert!(index_writer.commit().is_ok());
            for _ in 0..200 {
                index_writer.add_document(doc!(text_field=> LOREM))?;
            }
            assert!(index_writer.commit().is_ok());
        }
        assert_eq!(
            index.reader().unwrap().searcher().segment_readers()[0]
                .get_store_reader()
                .unwrap()
                .compressor(),
            Compressor::Lz4
        );
        // Change compressor, this disables stacking on merging
        let index_settings = index.settings_mut();
        index_settings.docstore_compression = Compressor::Snappy;
        // Merging the segments
        {
            let segment_ids = index
                .searchable_segment_ids()
                .expect("Searchable segments failed.");
            let mut index_writer = index.writer_for_tests().unwrap();
            assert!(block_on(index_writer.merge(&segment_ids)).is_ok());
            assert!(index_writer.wait_merging_threads().is_ok());
        }

        let searcher = index.reader().unwrap().searcher();
        assert_eq!(searcher.segment_readers().len(), 1);
        let reader = searcher.segment_readers().iter().last().unwrap();
        let store = reader.get_store_reader().unwrap();

        for doc in store.iter(reader.alive_bitset()).take(50) {
            assert_eq!(
                *doc?.get_first(text_field).unwrap().text().unwrap(),
                LOREM.to_string()
            );
        }
        assert_eq!(store.compressor(), Compressor::Snappy);

        Ok(())
    }

    #[test]
    fn test_merge_of_small_segments() -> crate::Result<()> {
        let mut schema_builder = schema::Schema::builder();

        let text_field = schema_builder.add_text_field("text_field", TEXT | STORED);
        let schema = schema_builder.build();
        let index_builder = Index::builder().schema(schema);

        let index = index_builder.create_in_ram().unwrap();

        {
            let mut index_writer = index.writer_for_tests()?;
            index_writer.add_document(doc!(text_field=> "1"))?;
            index_writer.commit()?;
            index_writer.add_document(doc!(text_field=> "2"))?;
            index_writer.commit()?;
            index_writer.add_document(doc!(text_field=> "3"))?;
            index_writer.commit()?;
            index_writer.add_document(doc!(text_field=> "4"))?;
            index_writer.commit()?;
            index_writer.add_document(doc!(text_field=> "5"))?;
            index_writer.commit()?;
        }
        // Merging the segments
        {
            let segment_ids = index.searchable_segment_ids()?;
            let mut index_writer = index.writer_for_tests()?;
            block_on(index_writer.merge(&segment_ids))?;
            index_writer.wait_merging_threads()?;
        }

        let searcher = index.reader()?.searcher();
        assert_eq!(searcher.segment_readers().len(), 1);
        let reader = searcher.segment_readers().iter().last().unwrap();
        let store = reader.get_store_reader()?;
        assert_eq!(store.block_checkpoints().count(), 1);
        Ok(())
    }
}

#[cfg(all(test, feature = "unstable"))]
mod bench {

    use std::path::Path;

    use test::Bencher;

    use super::tests::write_lorem_ipsum_store;
    use crate::directory::{Directory, RamDirectory};
    use crate::store::{Compressor, StoreReader};

    #[bench]
    #[cfg(feature = "mmap")]
    fn bench_store_encode(b: &mut Bencher) {
        let directory = RamDirectory::create();
        let path = Path::new("store");
        b.iter(|| {
            write_lorem_ipsum_store(
                directory.open_write(path).unwrap(),
                1_000,
                Compressor::default(),
            );
            directory.delete(path).unwrap();
        });
    }

    #[bench]
    fn bench_store_decode(b: &mut Bencher) {
        let directory = RamDirectory::create();
        let path = Path::new("store");
        write_lorem_ipsum_store(
            directory.open_write(path).unwrap(),
            1_000,
            Compressor::default(),
        );
        let store_file = directory.open_read(path).unwrap();
        let store = StoreReader::open(store_file).unwrap();
        b.iter(|| store.iter(None).collect::<Vec<_>>());
    }
}
<commit_msg>Fixing all-features build.<commit_after>//! Compressed/slow/row-oriented storage for documents.
//!
//! A field needs to be marked as stored in the schema in
//! order to be handled in the `Store`.
//!
//! Internally, documents (or rather their stored fields) are serialized to a buffer.
//! When the buffer exceeds 16K, the buffer is compressed using `brotli`, `LZ4` or `snappy`
//! and the resulting block is written to disk.
//!
//! One can then request for a specific `DocId`.
//! A skip list helps navigating to the right block,
//! decompresses it entirely and returns the document within it.
//!
//! If the last document requested was in the same block,
//! the reader is smart enough to avoid decompressing
//! the block a second time, but their is no real
//! uncompressed block* cache.
//!
//! A typical use case for the store is, once
//! the search result page has been computed, returning
//! the actual content of the 10 best document.
//!
//! # Usage
//!
//! Most users should not access the `StoreReader` directly
//! and should rely on either
//!
//! - at the segment level, the
//! [`SegmentReader`'s `doc` method](../struct.SegmentReader.html#method.doc)
//! - at the index level, the
//! [`Searcher`'s `doc` method](../struct.Searcher.html#method.doc)
//!
//! !

mod compressors;
mod footer;
mod index;
mod reader;
mod writer;
pub use self::compressors::Compressor;
pub use self::reader::StoreReader;
pub use self::writer::StoreWriter;

#[cfg(feature = "lz4-compression")]
mod compression_lz4_block;

#[cfg(feature = "brotli-compression")]
mod compression_brotli;

#[cfg(feature = "snappy-compression")]
mod compression_snap;

#[cfg(test)]
pub mod tests {

    use std::path::Path;

    use futures::executor::block_on;

    use super::*;
    use crate::directory::{Directory, RamDirectory, WritePtr};
    use crate::fastfield::AliveBitSet;
    use crate::schema::{
        self, Document, FieldValue, Schema, TextFieldIndexing, TextOptions, STORED, TEXT,
    };
    use crate::{Index, Term};

    const LOREM: &str = "Doc Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \
                         eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad \
                         minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip \
                         ex ea commodo consequat. Duis aute irure dolor in reprehenderit in \
                         voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur \
                         sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt \
                         mollit anim id est laborum.";

    pub fn write_lorem_ipsum_store(
        writer: WritePtr,
        num_docs: usize,
        compressor: Compressor,
    ) -> Schema {
        let mut schema_builder = Schema::builder();
        let field_body = schema_builder.add_text_field("body", TextOptions::default().set_stored());
        let field_title =
            schema_builder.add_text_field("title", TextOptions::default().set_stored());
        let schema = schema_builder.build();
        {
            let mut store_writer = StoreWriter::new(writer, compressor);
            for i in 0..num_docs {
                let mut fields: Vec<FieldValue> = Vec::new();
                {
                    let field_value = FieldValue::new(field_body, From::from(LOREM.to_string()));
                    fields.push(field_value);
                }
                {
                    let title_text = format!("Doc {}", i);
                    let field_value = FieldValue::new(field_title, From::from(title_text));
                    fields.push(field_value);
                }
                // let fields_refs: Vec<&FieldValue> = fields.iter().collect();
                let doc = Document::from(fields);
                store_writer.store(&doc).unwrap();
            }
            store_writer.close().unwrap();
        }
        schema
    }

    const NUM_DOCS: usize = 1_000;
    #[test]
    fn test_doc_store_iter_with_delete_bug_1077() -> crate::Result<()> {
        // this will cover deletion of the first element in a checkpoint
        let deleted_doc_ids = (200..300).collect::<Vec<_>>();
        let alive_bitset =
            AliveBitSet::for_test_from_deleted_docs(&deleted_doc_ids, NUM_DOCS as u32);

        let path = Path::new("store");
        let directory = RamDirectory::create();
        let store_wrt = directory.open_write(path)?;
        let schema = write_lorem_ipsum_store(store_wrt, NUM_DOCS, Compressor::Lz4);
        let field_title = schema.get_field("title").unwrap();
        let store_file = directory.open_read(path)?;
        let store = StoreReader::open(store_file)?;
        for i in 0..NUM_DOCS as u32 {
            assert_eq!(
                *store
                    .get(i)?
                    .get_first(field_title)
                    .unwrap()
                    .as_text()
                    .unwrap(),
                format!("Doc {}", i)
            );
        }

        for (_, doc) in store.iter(Some(&alive_bitset)).enumerate() {
            let doc = doc?;
            let title_content = doc.get_first(field_title).unwrap().as_text().unwrap();
            if !title_content.starts_with("Doc ") {
                panic!("unexpected title_content {}", title_content);
            }

            let id = title_content
                .strip_prefix("Doc ")
                .unwrap()
                .parse::<u32>()
                .unwrap();
            if alive_bitset.is_deleted(id) {
                panic!("unexpected deleted document {}", id);
            }
        }

        Ok(())
    }

    fn test_store(compressor: Compressor) -> crate::Result<()> {
        let path = Path::new("store");
        let directory = RamDirectory::create();
        let store_wrt = directory.open_write(path)?;
        let schema = write_lorem_ipsum_store(store_wrt, NUM_DOCS, compressor);
        let field_title = schema.get_field("title").unwrap();
        let store_file = directory.open_read(path)?;
        let store = StoreReader::open(store_file)?;
        for i in 0..NUM_DOCS as u32 {
            assert_eq!(
                *store
                    .get(i)?
                    .get_first(field_title)
                    .unwrap()
                    .as_text()
                    .unwrap(),
                format!("Doc {}", i)
            );
        }
        for (i, doc) in store.iter(None).enumerate() {
            assert_eq!(
                *doc?.get_first(field_title).unwrap().as_text().unwrap(),
                format!("Doc {}", i)
            );
        }
        Ok(())
    }

    #[test]
    fn test_store_noop() -> crate::Result<()> {
        test_store(Compressor::None)
    }
    #[cfg(feature = "lz4-compression")]
    #[test]
    fn test_store_lz4_block() -> crate::Result<()> {
        test_store(Compressor::Lz4)
    }
    #[cfg(feature = "snappy-compression")]
    #[test]
    fn test_store_snap() -> crate::Result<()> {
        test_store(Compressor::Snappy)
    }
    #[cfg(feature = "brotli-compression")]
    #[test]
    fn test_store_brotli() -> crate::Result<()> {
        test_store(Compressor::Brotli)
    }

    #[test]
    fn test_store_with_delete() -> crate::Result<()> {
        let mut schema_builder = schema::Schema::builder();

        let text_field_options = TextOptions::default()
            .set_indexing_options(
                TextFieldIndexing::default()
                    .set_index_option(schema::IndexRecordOption::WithFreqsAndPositions),
            )
            .set_stored();
        let text_field = schema_builder.add_text_field("text_field", text_field_options);
        let schema = schema_builder.build();
        let index_builder = Index::builder().schema(schema);

        let index = index_builder.create_in_ram()?;

        {
            let mut index_writer = index.writer_for_tests().unwrap();
            index_writer.add_document(doc!(text_field=> "deleteme"))?;
            index_writer.add_document(doc!(text_field=> "deletemenot"))?;
            index_writer.add_document(doc!(text_field=> "deleteme"))?;
            index_writer.add_document(doc!(text_field=> "deletemenot"))?;
            index_writer.add_document(doc!(text_field=> "deleteme"))?;

            index_writer.delete_term(Term::from_field_text(text_field, "deleteme"));
            index_writer.commit()?;
        }

        let searcher = index.reader()?.searcher();
        let reader = searcher.segment_reader(0);
        let store = reader.get_store_reader()?;
        for doc in store.iter(reader.alive_bitset()) {
            assert_eq!(
                *doc?.get_first(text_field).unwrap().as_text().unwrap(),
                "deletemenot".to_string()
            );
        }
        Ok(())
    }

    #[cfg(feature = "snappy-compression")]
    #[cfg(feature = "lz4-compression")]
    #[test]
    fn test_merge_with_changed_compressor() -> crate::Result<()> {
        let mut schema_builder = schema::Schema::builder();

        let text_field = schema_builder.add_text_field("text_field", TEXT | STORED);
        let schema = schema_builder.build();
        let index_builder = Index::builder().schema(schema);

        let mut index = index_builder.create_in_ram().unwrap();
        index.settings_mut().docstore_compression = Compressor::Lz4;
        {
            let mut index_writer = index.writer_for_tests().unwrap();
            // put enough data create enough blocks in the doc store to be considered for stacking
            for _ in 0..200 {
                index_writer.add_document(doc!(text_field=> LOREM))?;
            }
            assert!(index_writer.commit().is_ok());
            for _ in 0..200 {
                index_writer.add_document(doc!(text_field=> LOREM))?;
            }
            assert!(index_writer.commit().is_ok());
        }
        assert_eq!(
            index.reader().unwrap().searcher().segment_readers()[0]
                .get_store_reader()
                .unwrap()
                .compressor(),
            Compressor::Lz4
        );
        // Change compressor, this disables stacking on merging
        let index_settings = index.settings_mut();
        index_settings.docstore_compression = Compressor::Snappy;
        // Merging the segments
        {
            let segment_ids = index
                .searchable_segment_ids()
                .expect("Searchable segments failed.");
            let mut index_writer = index.writer_for_tests().unwrap();
            assert!(block_on(index_writer.merge(&segment_ids)).is_ok());
            assert!(index_writer.wait_merging_threads().is_ok());
        }

        let searcher = index.reader().unwrap().searcher();
        assert_eq!(searcher.segment_readers().len(), 1);
        let reader = searcher.segment_readers().iter().last().unwrap();
        let store = reader.get_store_reader().unwrap();

        for doc in store.iter(reader.alive_bitset()).take(50) {
            assert_eq!(
                *doc?.get_first(text_field).unwrap().as_text().unwrap(),
                LOREM.to_string()
            );
        }
        assert_eq!(store.compressor(), Compressor::Snappy);

        Ok(())
    }

    #[test]
    fn test_merge_of_small_segments() -> crate::Result<()> {
        let mut schema_builder = schema::Schema::builder();

        let text_field = schema_builder.add_text_field("text_field", TEXT | STORED);
        let schema = schema_builder.build();
        let index_builder = Index::builder().schema(schema);

        let index = index_builder.create_in_ram().unwrap();

        {
            let mut index_writer = index.writer_for_tests()?;
            index_writer.add_document(doc!(text_field=> "1"))?;
            index_writer.commit()?;
            index_writer.add_document(doc!(text_field=> "2"))?;
            index_writer.commit()?;
            index_writer.add_document(doc!(text_field=> "3"))?;
            index_writer.commit()?;
            index_writer.add_document(doc!(text_field=> "4"))?;
            index_writer.commit()?;
            index_writer.add_document(doc!(text_field=> "5"))?;
            index_writer.commit()?;
        }
        // Merging the segments
        {
            let segment_ids = index.searchable_segment_ids()?;
            let mut index_writer = index.writer_for_tests()?;
            block_on(index_writer.merge(&segment_ids))?;
            index_writer.wait_merging_threads()?;
        }

        let searcher = index.reader()?.searcher();
        assert_eq!(searcher.segment_readers().len(), 1);
        let reader = searcher.segment_readers().iter().last().unwrap();
        let store = reader.get_store_reader()?;
        assert_eq!(store.block_checkpoints().count(), 1);
        Ok(())
    }
}

#[cfg(all(test, feature = "unstable"))]
mod bench {

    use std::path::Path;

    use test::Bencher;

    use super::tests::write_lorem_ipsum_store;
    use crate::directory::{Directory, RamDirectory};
    use crate::store::{Compressor, StoreReader};

    #[bench]
    #[cfg(feature = "mmap")]
    fn bench_store_encode(b: &mut Bencher) {
        let directory = RamDirectory::create();
        let path = Path::new("store");
        b.iter(|| {
            write_lorem_ipsum_store(
                directory.open_write(path).unwrap(),
                1_000,
                Compressor::default(),
            );
            directory.delete(path).unwrap();
        });
    }

    #[bench]
    fn bench_store_decode(b: &mut Bencher) {
        let directory = RamDirectory::create();
        let path = Path::new("store");
        write_lorem_ipsum_store(
            directory.open_write(path).unwrap(),
            1_000,
            Compressor::default(),
        );
        let store_file = directory.open_read(path).unwrap();
        let store = StoreReader::open(store_file).unwrap();
        b.iter(|| store.iter(None).collect::<Vec<_>>());
    }
}
<|endoftext|>


<commit_before>//! Contains types used in this library
use std::convert::From;
use std::ops::{ Add, Mul, Sub };

pub use math::{ Matrix2d, Scalar, Vec2d };

/// The size of a shape.
#[derive(Clone, Copy, Debug)]
pub struct Size {
    width: Scalar,
    height: Scalar,
}

impl From<Vec2d> for Size {
    fn from(v: Vec2d) -> Size {
        Size { width: v[0], height: v[1] }
    }
}

impl Size {
    /// Convert size to a vector.
    pub fn to_vec2d(&self) -> Vec2d {
        [self.width, self.height]
    }
}

impl Mul<Vec2d> for Size {
    type Output = Size;

    fn mul(self, v: Vec2d) -> Size {
        Size { width: self.width * v[0], height: self.height * v[1] }
    }
}

impl Mul<Scalar> for Size {
    type Output = Size;

    fn mul(self, s: Scalar) -> Size {
        Size { width: self.width * s, height: self.height * s }
    }
}

/// A point in the Cartesian plane.
#[derive(Clone, Copy, Debug)]
pub struct Point {
    x: Scalar,
    y: Scalar,
}

impl Add<Scalar> for Point {
    type Output = Point;

    fn add(self, s: Scalar) -> Point {
        Point { x: self.x + s, y: self.y + s }
    }
}

impl Add<Vec2d> for Point {
    type Output = Point;

    fn add(self, v: Vec2d) -> Point {
        Point { x: self.x + v[0], y: self.y + v[1] }
    }
}

impl From<Vec2d> for Point {
    fn from(v: Vec2d) -> Point {
        Point { x: v[0], y: v[1] }
    }
}

impl Sub<Scalar> for Point {
    type Output = Point;

    fn sub(self, s: Scalar) -> Point {
        Point { x: self.x - s, y: self.y - s }
    }
}

impl Sub<Vec2d> for Point {
    type Output = Point;

    fn sub(self, v: Vec2d) -> Point {
        Point { x: self.x - v[0], y: self.y - v[1] }
    }
}

impl Point {
    /// Convert the point to a vector.
    pub fn to_vec2d(&self) -> Vec2d {
        [self.x, self.y]
    }
}

/// A rectangle whose top left corner is at pos.
#[derive(Clone, Copy, Debug)]
pub struct Rect {
    pos: Point,
    size: Size,
}

impl From<(Point, Size)> for Rect {
    /// Creates a rectangle from the position of its top left corner and its size.
    fn from(rectangle: (Point, Size)) -> Rect {
        let (pos, size) = rectangle;
        Rect { pos: pos, size: size }
    }
}

impl From<[Scalar; 4]> for Rect {
    /// Creates a rectangle from an array.
    fn from(v: [Scalar; 4]) -> Rect {
        Rect {
            pos: Point { x: v[0], y: v[1] },
            size: Size { width: v[2], height: v[3] },
        }
    }
}

impl Rect {
    /// Returns the position of the bottom side of the rectangle.
    pub fn bottom(&self) -> Scalar {
        self.pos.y + self.size.height
    }

    /// Computes a rectangle with quadruple the surface area of self and with center
    /// (self.x, self.y).
    pub fn centered(&self) -> Rect {
        Rect {
            pos: Point {
                 x: self.pos.x - self.size.width,
                 y: self.pos.y - self.size.height,
            },
            size: self.size * 2.0,
        }
    }

    /// Compute whether or not the point is inside the rectangle.
    #[inline]
    pub fn contains(&self, point: Point) -> bool {
        self.left() < point.x && point.x < self.right() &&
        self.top() < point.y && point.y < self.bottom()
    }

    /// Create a rectangle that circumscribes the given circle.
    pub fn from_circle(center: Point, radius: Scalar) -> Rect {
        Rect {
            pos: Point {
                x: center.x - radius,
                y: center.y - radius,
            },
            size: Size {
                width: 2.0 * radius,
                height: 2.0 * radius,
            },
        }
    }

    /// Create a square rectangle with sides of length len and top left corner at pos.
    pub fn from_square(pos: Point, len: Scalar) -> Rect {
        Rect {
            pos: pos,
            size: Size { width: len, height: len },
        }
    }

    /// Converts a rectangle into [x, y, w, h].
    pub fn into_array(self) -> [Scalar; 4] {
        [self.pos.x, self.pos.y, self.size.width, self.size.height]
    }

    /// Returns the position of the left side of the rectangle.
    pub fn left(&self) -> Scalar {
        self.pos.x
    }

    /// Computes a rectangle whose perimeter forms the inside edge of margin with size m for self.
    #[inline(always)]
    pub fn margin(&self, m: Scalar) -> Rect {
        let w = self.size.width - 2.0 * m;
        let h = self.size.height - 2.0 * m;
        let (x, w)
            =   if w < 0.0 {
                    (self.pos.x + 0.5 * self.size.width, 0.0)
                } else {
                    (self.pos.x + m, w)
                };
        let (y, h)
            =   if h < 0.0 {
                    (self.pos.y + 0.5 * self.size.height, 0.0)
                } else {
                    (self.pos.y + m, h)
                };

        Rect {
            pos: Point { x: x, y: y },
            size: Size { width: w, height: h },
        }
    }

    /// Computes a rectangle translated (slid) in the direction of the vector a distance relative
    /// to the size of the rectangle. For example, self.relative([1.0, 1.0]) returns a rectangle
    /// one rectangle to the right and down from the original.
    #[inline(always)]
    pub fn relative(&self, v: Vec2d) -> Rect {
        Rect {
            pos: self.pos + (self.size * v).to_vec2d(),
            size: self.size,
        }
    }

    /// Returns the position of the right side of the rectangle.
    pub fn right(&self) -> Scalar {
        self.pos.x + self.size.width
    }

    /// Computes a scaled rectangle with the same position as self.
    pub fn scaled(&self, v: Vec2d) -> Rect {
        Rect {
            pos: self.pos,
            size: self.size * v,
        }
    }

    /// Converts a rectangle to [x, y, w, h].
    pub fn to_array(&self) -> [Scalar; 4] {
        [self.pos.x, self.pos.y, self.size.width, self.size.height]
    }

    /// Returns the position of the top side of the rectangle.
    pub fn top(&self) -> Scalar {
        self.pos.y
    }
}
<commit_msg>make all of the struct members public and add documentation<commit_after>//! Contains types used in this library
use std::convert::From;
use std::ops::{ Add, Mul, Sub };

pub use math::{ Matrix2d, Scalar, Vec2d };

/// The size of a shape.
#[derive(Clone, Copy, Debug)]
pub struct Size {
    /// The horizontal length of the shape.
    pub width: Scalar,
    /// The vertical length of the shape.
    pub height: Scalar,
}

impl From<Vec2d> for Size {
    fn from(v: Vec2d) -> Size {
        Size { width: v[0], height: v[1] }
    }
}

impl Size {
    /// Convert size to a vector.
    pub fn to_vec2d(&self) -> Vec2d {
        [self.width, self.height]
    }
}

impl Mul<Vec2d> for Size {
    type Output = Size;

    fn mul(self, v: Vec2d) -> Size {
        Size { width: self.width * v[0], height: self.height * v[1] }
    }
}

impl Mul<Scalar> for Size {
    type Output = Size;

    fn mul(self, s: Scalar) -> Size {
        Size { width: self.width * s, height: self.height * s }
    }
}

/// A point in the Cartesian plane.
#[derive(Clone, Copy, Debug)]
pub struct Point {
    /// The x coordinate.
    pub x: Scalar,
    /// The y coordinate.
    pub y: Scalar,
}

impl Add<Scalar> for Point {
    type Output = Point;

    fn add(self, s: Scalar) -> Point {
        Point { x: self.x + s, y: self.y + s }
    }
}

impl Add<Vec2d> for Point {
    type Output = Point;

    fn add(self, v: Vec2d) -> Point {
        Point { x: self.x + v[0], y: self.y + v[1] }
    }
}

impl From<Vec2d> for Point {
    fn from(v: Vec2d) -> Point {
        Point { x: v[0], y: v[1] }
    }
}

impl Sub<Scalar> for Point {
    type Output = Point;

    fn sub(self, s: Scalar) -> Point {
        Point { x: self.x - s, y: self.y - s }
    }
}

impl Sub<Vec2d> for Point {
    type Output = Point;

    fn sub(self, v: Vec2d) -> Point {
        Point { x: self.x - v[0], y: self.y - v[1] }
    }
}

impl Point {
    /// Convert the point to a vector.
    pub fn to_vec2d(&self) -> Vec2d {
        [self.x, self.y]
    }
}

/// A rectangle.
#[derive(Clone, Copy, Debug)]
pub struct Rect {
    /// The position of the top left corner of the rectangle.
    pub pos: Point,
    /// The width and height of the rectangle.
    pub size: Size,
}

impl From<(Point, Size)> for Rect {
    /// Creates a rectangle from the position of its top left corner and its size.
    fn from(rectangle: (Point, Size)) -> Rect {
        let (pos, size) = rectangle;
        Rect { pos: pos, size: size }
    }
}

impl From<[Scalar; 4]> for Rect {
    /// Creates a rectangle from an array.
    fn from(v: [Scalar; 4]) -> Rect {
        Rect {
            pos: Point { x: v[0], y: v[1] },
            size: Size { width: v[2], height: v[3] },
        }
    }
}

impl Rect {
    /// Returns the position of the bottom side of the rectangle.
    pub fn bottom(&self) -> Scalar {
        self.pos.y + self.size.height
    }

    /// Computes a rectangle with quadruple the surface area of self and with center
    /// (self.x, self.y).
    pub fn centered(&self) -> Rect {
        Rect {
            pos: Point {
                 x: self.pos.x - self.size.width,
                 y: self.pos.y - self.size.height,
            },
            size: self.size * 2.0,
        }
    }

    /// Compute whether or not the point is inside the rectangle.
    #[inline]
    pub fn contains(&self, point: Point) -> bool {
        self.left() < point.x && point.x < self.right() &&
        self.top() < point.y && point.y < self.bottom()
    }

    /// Create a rectangle that circumscribes the given circle.
    pub fn from_circle(center: Point, radius: Scalar) -> Rect {
        Rect {
            pos: Point {
                x: center.x - radius,
                y: center.y - radius,
            },
            size: Size {
                width: 2.0 * radius,
                height: 2.0 * radius,
            },
        }
    }

    /// Create a square rectangle with sides of length len and top left corner at pos.
    pub fn from_square(pos: Point, len: Scalar) -> Rect {
        Rect {
            pos: pos,
            size: Size { width: len, height: len },
        }
    }

    /// Converts a rectangle into [x, y, w, h].
    pub fn into_array(self) -> [Scalar; 4] {
        [self.pos.x, self.pos.y, self.size.width, self.size.height]
    }

    /// Returns the position of the left side of the rectangle.
    pub fn left(&self) -> Scalar {
        self.pos.x
    }

    /// Computes a rectangle whose perimeter forms the inside edge of margin with size m for self.
    #[inline(always)]
    pub fn margin(&self, m: Scalar) -> Rect {
        let w = self.size.width - 2.0 * m;
        let h = self.size.height - 2.0 * m;
        let (x, w)
            =   if w < 0.0 {
                    (self.pos.x + 0.5 * self.size.width, 0.0)
                } else {
                    (self.pos.x + m, w)
                };
        let (y, h)
            =   if h < 0.0 {
                    (self.pos.y + 0.5 * self.size.height, 0.0)
                } else {
                    (self.pos.y + m, h)
                };

        Rect {
            pos: Point { x: x, y: y },
            size: Size { width: w, height: h },
        }
    }

    /// Computes a rectangle translated (slid) in the direction of the vector a distance relative
    /// to the size of the rectangle. For example, self.relative([1.0, 1.0]) returns a rectangle
    /// one rectangle to the right and down from the original.
    #[inline(always)]
    pub fn relative(&self, v: Vec2d) -> Rect {
        Rect {
            pos: self.pos + (self.size * v).to_vec2d(),
            size: self.size,
        }
    }

    /// Returns the position of the right side of the rectangle.
    pub fn right(&self) -> Scalar {
        self.pos.x + self.size.width
    }

    /// Computes a scaled rectangle with the same position as self.
    pub fn scaled(&self, v: Vec2d) -> Rect {
        Rect {
            pos: self.pos,
            size: self.size * v,
        }
    }

    /// Converts a rectangle to [x, y, w, h].
    pub fn to_array(&self) -> [Scalar; 4] {
        [self.pos.x, self.pos.y, self.size.width, self.size.height]
    }

    /// Returns the position of the top side of the rectangle.
    pub fn top(&self) -> Scalar {
        self.pos.y
    }
}
<|endoftext|>


<commit_before>use time::now;
use libc::funcs::posix88::unistd::getpid;
use std::io::fs::{mkdir_recursive, mkdir, link, readdir, copy, rename};
use std::io::fs::PathExtensions;
use std::io::{FilePermission, TypeSymlink};
use std::io;

use super::super::env::{Environ, Container};
use super::super::config::{Command, WriteMode};
use super::super::config::{ReadOnly, TransientHardLinkCopy};
use super::super::clean::run_rmdirs;
use super::super::linux::{Mount, Pseudo, Bind, ensure_dir};

pub fn check_command_workdir(env: &Environ, command: &Command)
    -> Result<Path, String>
{
    if command.work_dir.is_some() {
        let ncwd = env.project_root.join(
            command.work_dir.as_ref().unwrap().as_slice());
        if !env.project_root.is_ancestor_of(&ncwd) {
            return Err(format!("Command's work-dir must be relative to \
                project root"));
        }
        return Ok(ncwd);
    } else {
        return Ok(env.work_dir.clone());
    }
}

struct WriteSentinel {
    vagga_exe: Path,
    dir_to_delete: Option<Path>,
}

impl Drop for WriteSentinel {
    fn drop(&mut self) {
        match self.dir_to_delete {
            Some(ref path) => {
                run_rmdirs(&self.vagga_exe, vec!(path.clone())).unwrap();
            }
            None => {}
        }
    }
}

fn clone_dir(src: &Path, target: &Path) -> Result<(), String> {
    let items = try!(readdir(src)
        .map_err(|e| format!("Failed to read dir: {}", e)));
    for item in items.iter() {
        let stat = try!(item.lstat()
            .map_err(|e| format!("Failed to stat file: {}", e)));
        let tpath = target.join(item.path_relative_from(src).unwrap());
        match stat.kind {
            io::TypeFile | io::TypeSymlink => {
                try!(link(item, &tpath)
                    .map_err(|e| format!("Failed to hardlink file: {}", e)));
            }
            io::TypeDirectory => {
                try!(mkdir(&tpath, stat.perm)
                    .map_err(|e| format!("Failed to make directory: {}", e)));
                try!(clone_dir(item, &tpath));
            }
            io::TypeNamedPipe|io::TypeBlockSpecial|io::TypeUnknown => {
                warn!("Ignoring special file: {}", item.display());
            }
        }
    }
    return Ok(());
}

pub fn write_sentinel(env: &Environ, container: &mut Container,
    write_mode: WriteMode)
    -> Result<WriteSentinel, String>
{
    let mut res = WriteSentinel {
        vagga_exe: env.vagga_exe.clone(),
        dir_to_delete: None,
    };
    match write_mode {
        ReadOnly => {}
        TransientHardLinkCopy => {
            let time = now();
            let name = format!(
                "{}.{year:04d}{mon:02d}{mday:02d}.{}",
                container.name, unsafe { getpid() },
                year=time.tm_year, mon=time.tm_mon, mday=time.tm_mday);
            let path = env.local_vagga.join(".transients").join(name);
            try!(mkdir_recursive(&path, FilePermission::all())
                .map_err(|e| format!("Can't create container dir: {}", e)));
            res.dir_to_delete = Some(path.clone());

            try!(clone_dir(container.container_root.as_ref().unwrap(), &path));
            container.container_root = Some(path);
        }
    }
    return Ok(res);
}

pub fn is_writeable(val: WriteMode) -> bool {
    return match val {
        ReadOnly => false,
        TransientHardLinkCopy => true,
    };
}

pub fn print_banner(val: &Option<String>) {
    match *val {
        None => {}
        Some(ref x) => {
            if x.len() == 0 || x.as_slice().chars().last().unwrap() != '\n' {
                println!("{}", x);
            } else {
                print!("{}", x);
            }
        }
    }
}

pub fn container_volumes(env: &Environ, container: &Container) -> Vec<Mount> {
    let mount_dir = env.local_vagga.join(".mnt");
    let root = Path::new("/");
    let mut mounts: Vec<Mount> = vec!();
    mounts.extend(container.tmpfs_volumes.iter()
        .map(|&(ref dir, ref opts)|
            Pseudo("tmpfs".to_c_str(),
            mount_dir.join(dir.path_relative_from(&root).unwrap()).to_c_str(),
            opts.to_c_str())));
    mounts.extend(container.mutable_dirs.iter()
        .map(|ref path| {
            let dir = mount_dir.join(path.path_relative_from(&root).unwrap());
            Bind(dir.to_c_str(), dir.to_c_str())
        }));
    return mounts;
}

pub fn write_resolv_conf(root: &Path, subdir: &Path)
    -> Result<(), String>
{
    assert!(subdir.is_absolute());
    let dir = root.join(subdir.path_relative_from(&Path::new("/")).unwrap());
    try!(ensure_dir(&dir));
    println!("SUBDIR {}", dir.display());
    try!(copy(&Path::new("/etc/resolv.conf"),
              &dir.join("resolv.conf.tmp"))
        .map_err(|e| format!("Error copying resolv.conf: {}", e)));
    try!(rename(&dir.join("resolv.conf.tmp"),
                &dir.join("resolv.conf"),)
        .map_err(|e| format!("Error copying resolv.conf: {}", e)));
    return Ok(());
}
<commit_msg>Remove debugging print<commit_after>use time::now;
use libc::funcs::posix88::unistd::getpid;
use std::io::fs::{mkdir_recursive, mkdir, link, readdir, copy, rename};
use std::io::fs::PathExtensions;
use std::io::{FilePermission, TypeSymlink};
use std::io;

use super::super::env::{Environ, Container};
use super::super::config::{Command, WriteMode};
use super::super::config::{ReadOnly, TransientHardLinkCopy};
use super::super::clean::run_rmdirs;
use super::super::linux::{Mount, Pseudo, Bind, ensure_dir};

pub fn check_command_workdir(env: &Environ, command: &Command)
    -> Result<Path, String>
{
    if command.work_dir.is_some() {
        let ncwd = env.project_root.join(
            command.work_dir.as_ref().unwrap().as_slice());
        if !env.project_root.is_ancestor_of(&ncwd) {
            return Err(format!("Command's work-dir must be relative to \
                project root"));
        }
        return Ok(ncwd);
    } else {
        return Ok(env.work_dir.clone());
    }
}

struct WriteSentinel {
    vagga_exe: Path,
    dir_to_delete: Option<Path>,
}

impl Drop for WriteSentinel {
    fn drop(&mut self) {
        match self.dir_to_delete {
            Some(ref path) => {
                run_rmdirs(&self.vagga_exe, vec!(path.clone())).unwrap();
            }
            None => {}
        }
    }
}

fn clone_dir(src: &Path, target: &Path) -> Result<(), String> {
    let items = try!(readdir(src)
        .map_err(|e| format!("Failed to read dir: {}", e)));
    for item in items.iter() {
        let stat = try!(item.lstat()
            .map_err(|e| format!("Failed to stat file: {}", e)));
        let tpath = target.join(item.path_relative_from(src).unwrap());
        match stat.kind {
            io::TypeFile | io::TypeSymlink => {
                try!(link(item, &tpath)
                    .map_err(|e| format!("Failed to hardlink file: {}", e)));
            }
            io::TypeDirectory => {
                try!(mkdir(&tpath, stat.perm)
                    .map_err(|e| format!("Failed to make directory: {}", e)));
                try!(clone_dir(item, &tpath));
            }
            io::TypeNamedPipe|io::TypeBlockSpecial|io::TypeUnknown => {
                warn!("Ignoring special file: {}", item.display());
            }
        }
    }
    return Ok(());
}

pub fn write_sentinel(env: &Environ, container: &mut Container,
    write_mode: WriteMode)
    -> Result<WriteSentinel, String>
{
    let mut res = WriteSentinel {
        vagga_exe: env.vagga_exe.clone(),
        dir_to_delete: None,
    };
    match write_mode {
        ReadOnly => {}
        TransientHardLinkCopy => {
            let time = now();
            let name = format!(
                "{}.{year:04d}{mon:02d}{mday:02d}.{}",
                container.name, unsafe { getpid() },
                year=time.tm_year, mon=time.tm_mon, mday=time.tm_mday);
            let path = env.local_vagga.join(".transients").join(name);
            try!(mkdir_recursive(&path, FilePermission::all())
                .map_err(|e| format!("Can't create container dir: {}", e)));
            res.dir_to_delete = Some(path.clone());

            try!(clone_dir(container.container_root.as_ref().unwrap(), &path));
            container.container_root = Some(path);
        }
    }
    return Ok(res);
}

pub fn is_writeable(val: WriteMode) -> bool {
    return match val {
        ReadOnly => false,
        TransientHardLinkCopy => true,
    };
}

pub fn print_banner(val: &Option<String>) {
    match *val {
        None => {}
        Some(ref x) => {
            if x.len() == 0 || x.as_slice().chars().last().unwrap() != '\n' {
                println!("{}", x);
            } else {
                print!("{}", x);
            }
        }
    }
}

pub fn container_volumes(env: &Environ, container: &Container) -> Vec<Mount> {
    let mount_dir = env.local_vagga.join(".mnt");
    let root = Path::new("/");
    let mut mounts: Vec<Mount> = vec!();
    mounts.extend(container.tmpfs_volumes.iter()
        .map(|&(ref dir, ref opts)|
            Pseudo("tmpfs".to_c_str(),
            mount_dir.join(dir.path_relative_from(&root).unwrap()).to_c_str(),
            opts.to_c_str())));
    mounts.extend(container.mutable_dirs.iter()
        .map(|ref path| {
            let dir = mount_dir.join(path.path_relative_from(&root).unwrap());
            Bind(dir.to_c_str(), dir.to_c_str())
        }));
    return mounts;
}

pub fn write_resolv_conf(root: &Path, subdir: &Path)
    -> Result<(), String>
{
    assert!(subdir.is_absolute());
    let dir = root.join(subdir.path_relative_from(&Path::new("/")).unwrap());
    try!(ensure_dir(&dir));
    try!(copy(&Path::new("/etc/resolv.conf"),
              &dir.join("resolv.conf.tmp"))
        .map_err(|e| format!("Error copying resolv.conf: {}", e)));
    try!(rename(&dir.join("resolv.conf.tmp"),
                &dir.join("resolv.conf"),)
        .map_err(|e| format!("Error copying resolv.conf: {}", e)));
    return Ok(());
}
<|endoftext|>


<commit_before>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Joseph Crail <jbcrail@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#[cfg(unix)]
use super::libc;
use std::env;
use std::fs;
use std::io::{Error, ErrorKind, Result};
use std::path::{Component, Path, PathBuf};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CanonicalizeMode {
    None,
    Normal,
    Existing,
    Missing,
}

fn resolve<P: AsRef<Path>>(original: P) -> Result<PathBuf> {
    const MAX_LINKS_FOLLOWED: u32 = 255;
    let mut followed = 0;
    let mut result = original.as_ref().to_path_buf();
    loop {
        if followed == MAX_LINKS_FOLLOWED {
            return Err(Error::new(ErrorKind::InvalidInput, "maximum links followed"));
        }

        match fs::metadata(&result) {
            Err(e) => return Err(e),
            Ok(ref m) if !m.file_type().is_symlink() => break,
            Ok(..) => {
                followed += 1;
                match fs::read_link(&result) {
                    Ok(path) => {
                        result.pop();
                        result.push(path);
                    },
                    Err(e) => {
                        return Err(e);
                    }
                }
            }
        }
    }
    Ok(result)
}

pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> Result<PathBuf> {
    // Create an absolute path
    let original = original.as_ref();
    let original = if original.is_absolute() {
        original.to_path_buf()
    } else {
        env::current_dir().unwrap().join(original)
    };

    let mut result = PathBuf::new();
    let mut parts = vec!();

    // Split path by directory separator; add prefix (Windows-only) and root
    // directory to final path buffer; add remaining parts to temporary
    // vector for canonicalization.
    for part in original.components() {
        match part {
            Component::Prefix(_) | Component::RootDir => {
                result.push(part.as_os_str());
            },
            Component::CurDir => {},
            Component::ParentDir => {
                parts.pop();
            },
            Component::Normal(_) => {
                parts.push(part.as_os_str());
            }
        }
    }

    // Resolve the symlinks where possible
    if !parts.is_empty() {
        for part in parts[..parts.len()-1].iter() {
            result.push(part);

            if can_mode == CanonicalizeMode::None {
                continue;
            }

            match resolve(&result) {
                Err(e) => match can_mode {
                    CanonicalizeMode::Missing => continue,
                    _ => return Err(e)
                },
                Ok(path) => {
                    result.pop();
                    result.push(path);
                }
            }
        }

        result.push(parts.last().unwrap());

        match resolve(&result) {
            Err(e) => { if can_mode == CanonicalizeMode::Existing { return Err(e); } },
            Ok(path) => {
                result.pop();
                result.push(path);
            }
        }
    }
    Ok(result)
}

#[cfg(unix)]
pub fn is_stdin_interactive() -> bool {
    unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdin_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stdout_interactive() -> bool {
    unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdout_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stderr_interactive() -> bool {
    unsafe { libc::isatty(libc::STDERR_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stderr_interactive() -> bool {
    false
}
<commit_msg>uucore: don't follow symlinks when examining them (fixes #799)<commit_after>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Joseph Crail <jbcrail@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#[cfg(unix)]
use super::libc;
use std::env;
use std::fs;
use std::io::{Error, ErrorKind, Result};
use std::path::{Component, Path, PathBuf};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CanonicalizeMode {
    None,
    Normal,
    Existing,
    Missing,
}

fn resolve<P: AsRef<Path>>(original: P) -> Result<PathBuf> {
    const MAX_LINKS_FOLLOWED: u32 = 255;
    let mut followed = 0;
    let mut result = original.as_ref().to_path_buf();
    loop {
        if followed == MAX_LINKS_FOLLOWED {
            return Err(Error::new(ErrorKind::InvalidInput, "maximum links followed"));
        }

        match fs::symlink_metadata(&result) {
            Err(e) => return Err(e),
            Ok(ref m) if !m.file_type().is_symlink() => break,
            Ok(..) => {
                followed += 1;
                match fs::read_link(&result) {
                    Ok(path) => {
                        result.pop();
                        result.push(path);
                    },
                    Err(e) => {
                        return Err(e);
                    }
                }
            }
        }
    }
    Ok(result)
}

pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> Result<PathBuf> {
    // Create an absolute path
    let original = original.as_ref();
    let original = if original.is_absolute() {
        original.to_path_buf()
    } else {
        env::current_dir().unwrap().join(original)
    };

    let mut result = PathBuf::new();
    let mut parts = vec!();

    // Split path by directory separator; add prefix (Windows-only) and root
    // directory to final path buffer; add remaining parts to temporary
    // vector for canonicalization.
    for part in original.components() {
        match part {
            Component::Prefix(_) | Component::RootDir => {
                result.push(part.as_os_str());
            },
            Component::CurDir => {},
            Component::ParentDir => {
                parts.pop();
            },
            Component::Normal(_) => {
                parts.push(part.as_os_str());
            }
        }
    }

    // Resolve the symlinks where possible
    if !parts.is_empty() {
        for part in parts[..parts.len()-1].iter() {
            result.push(part);

            if can_mode == CanonicalizeMode::None {
                continue;
            }

            match resolve(&result) {
                Err(e) => match can_mode {
                    CanonicalizeMode::Missing => continue,
                    _ => return Err(e)
                },
                Ok(path) => {
                    result.pop();
                    result.push(path);
                }
            }
        }

        result.push(parts.last().unwrap());

        match resolve(&result) {
            Err(e) => { if can_mode == CanonicalizeMode::Existing { return Err(e); } },
            Ok(path) => {
                result.pop();
                result.push(path);
            }
        }
    }
    Ok(result)
}

#[cfg(unix)]
pub fn is_stdin_interactive() -> bool {
    unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdin_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stdout_interactive() -> bool {
    unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdout_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stderr_interactive() -> bool {
    unsafe { libc::isatty(libc::STDERR_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stderr_interactive() -> bool {
    false
}
<|endoftext|>


<commit_before>use utils::u256::U256;

pub trait Memory {
    fn write(&mut self, index: U256, value: U256);
    fn read(&mut self, index: U256) -> U256;
    fn active_len(&self) -> usize;
}

pub struct VectorMemory {
    memory: Vec<U256>,
}

impl VectorMemory {
    pub fn new() -> VectorMemory {
        VectorMemory {
            memory: Vec::new(),
        }
    }
}

impl Memory for VectorMemory {
    fn write(&mut self, index: U256, value: U256) {
        // Vector only deals with usize, so the maximum size is
        // actually smaller than 2^256
        let index_u64: u64 = index.into();
        let index = index_u64 as usize;

        if self.memory.len() <= index {
            self.memory.resize(index, 0.into());
        }

        self.memory[index] = value;
    }

    fn read(&mut self, index: U256) -> U256 {
        // This is required to be &mut self because a read might modify u_i

        let index_u64: u64 = index.into();
        let index = index_u64 as usize;

        if self.memory.len() <= index {
            self.memory.resize(index, 0.into());
        }

        match self.memory.get(index) {
            Some(&v) => v,
            None => 0.into()
        }
    }

    fn active_len(&self) -> usize {
        self.memory.len()
    }
}
<commit_msg>Problem: Memory is byte-indexed, not U256-indexed Solution: Fix memory implementation<commit_after>use utils::u256::U256;

pub trait Memory {
    fn write(&mut self, index: U256, value: U256);
    fn read(&mut self, index: U256) -> U256;
    fn active_len(&self) -> usize;
}

pub struct VectorMemory {
    memory: Vec<u8>,
}

impl VectorMemory {
    pub fn new() -> VectorMemory {
        VectorMemory {
            memory: Vec::new(),
        }
    }
}

impl Memory for VectorMemory {
    fn write(&mut self, index: U256, value: U256) {
        // Vector only deals with usize, so the maximum size is
        // actually smaller than 2^256
        let start: usize = index.into();
        let end = start + 32;

        if self.memory.len() <= end - 1 {
            self.memory.resize(end - 1, 0u8);
        }

        let a: &[u8] = value.as_ref();
        for i in start..end {
            self.memory[i] = a[i - start];
        }
    }

    fn read(&mut self, index: U256) -> U256 {
        // This is required to be &mut self because a read might modify u_i
        let start: usize = index.into();
        let end = start + 32;

        if self.memory.len() <= end - 1 {
            self.memory.resize(end - 1, 0.into());
        }

        let mut a: [u8; 32] = [0u8; 32];
        for i in start..end {
            a[i - start] = self.memory[i];
        }

        a.into()
    }

    fn active_len(&self) -> usize {
        self.memory.len()
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use azure::AzFloat;
use azure::azure_hl::Color as AzColor;

pub type Color = AzColor;

#[inline]
pub fn rgb(r: u8, g: u8, b: u8) -> AzColor {
    AzColor {
        r: (r as AzFloat) / (255.0 as AzFloat),
        g: (g as AzFloat) / (255.0 as AzFloat),
        b: (b as AzFloat) / (255.0 as AzFloat),
        a: 1.0 as AzFloat
    }
}

#[inline]
pub fn rgba(r: AzFloat, g: AzFloat, b: AzFloat, a: AzFloat) -> AzColor {
    AzColor { r: r, g: g, b: b, a: a }
}

#[inline]
pub fn black() -> AzColor {
    AzColor { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }
}

#[inline]
pub fn white() -> AzColor {
    AzColor { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }
}
<commit_msg>There are cases where we need opaque black (e.g. border color) and other cases where we need transparent black (e.g. clearing, root layers).<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use azure::AzFloat;
use azure::azure_hl::Color as AzColor;

pub type Color = AzColor;

#[inline]
pub fn rgb(r: u8, g: u8, b: u8) -> AzColor {
    AzColor {
        r: (r as AzFloat) / (255.0 as AzFloat),
        g: (g as AzFloat) / (255.0 as AzFloat),
        b: (b as AzFloat) / (255.0 as AzFloat),
        a: 1.0 as AzFloat
    }
}

#[inline]
pub fn rgba(r: AzFloat, g: AzFloat, b: AzFloat, a: AzFloat) -> AzColor {
    AzColor { r: r, g: g, b: b, a: a }
}

#[inline]
pub fn black() -> AzColor {
    AzColor { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }
}

#[inline]
pub fn transparent_black() -> AzColor {
    AzColor { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }
}

#[inline]
pub fn white() -> AzColor {
    AzColor { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Export the standard log style marcros under the log module. To use:
//    use crate::logger::log;
//    log::info("Something info...");
pub mod log {
    pub use tracing::debug;
    pub use tracing::error;
    pub use tracing::info;
    pub use tracing::trace;
    pub use tracing::warn;
}

pub fn init_logger(level: tracing::Level) {
    let timer =
        tracing_subscriber::fmt::time::ChronoLocal::with_format("%Y-%m-%d %H:%M:%S".to_string());
    let subscriber = tracing_subscriber::FmtSubscriber::builder()
        .with_max_level(level)
        .with_writer(std::io::stderr)
        .with_timer(timer)
        .finish();
    tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
}

pub fn init_stdlog() {
    tracing_log::LogTracer::builder()
        .with_max_level(stdlog::LevelFilter::Info)
        .init()
        .unwrap();
}
<commit_msg>logging: suppress hyper logs<commit_after>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Export the standard log style marcros under the log module. To use:
//    use crate::logger::log;
//    log::info("Something info...");
pub mod log {
    pub use tracing::debug;
    pub use tracing::error;
    pub use tracing::info;
    pub use tracing::trace;
    pub use tracing::warn;
}

use tracing::Level;

pub fn init_logger(level: Level) {
    let level = match level {
        Level::TRACE => "trace",
        Level::DEBUG => "debug",
        Level::INFO => "info",
        Level::WARN => "warn",
        Level::ERROR => "error",
    };
    let timer =
        tracing_subscriber::fmt::time::ChronoLocal::with_format("%Y-%m-%d %H:%M:%S".to_string());
    let subscriber = tracing_subscriber::FmtSubscriber::builder()
        .with_env_filter(format!("{},hyper=off", level))
        .with_writer(std::io::stderr)
        .with_timer(timer)
        .finish();
    tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
}

pub fn init_stdlog() {
    tracing_log::LogTracer::builder()
        .with_max_level(stdlog::LevelFilter::Info)
        .init()
        .unwrap();
}
<|endoftext|>


<commit_before>
#[macro_export]
macro_rules! impl_func_delegate {
	($name:ident) => (
		impl FuncDelegate for $name {
		    fn delegate(&mut self) -> &mut Function {
    		    &mut self.delegate
    		}
		}

	)
}

#[macro_export]
macro_rules! impl_mod_delegate {
	($name:ident) => (
		impl<T:Default+Copy> ModDelegate<T> for $name<T> {
		    fn delegate(&mut self) -> &mut Module<T> {
    		    &mut self.delegate
    		}
		}

	)
}

#[macro_export]
macro_rules! typecast {
    ($value:expr, $type:ident) => {$value as *mut $type}
}
<commit_msg>add macro for Functions taking no args<commit_after>
#[macro_export]
macro_rules! impl_func_delegate {
	($name:ident) => (
		impl FuncDelegate for $name {
		    fn delegate(&mut self) -> &mut Function {
    		    &mut self.delegate
    		}
		}

	)
}

#[macro_export]
macro_rules! impl_mod_delegate {
	($name:ident) => (
		impl<T:Default+Copy> ModDelegate<T> for $name<T> {
		    fn delegate(&mut self) -> &mut Module<T> {
    		    &mut self.delegate
    		}
		}

	)
}

#[macro_export]
macro_rules! typecast {
    ($value:expr, $type:ident) => {$value as *mut $type}
}

#[macro_export]
macro_rules! impl_func {
	($name:ident) => (
		#[derive(Clone)]
		pub struct $name {
    		delegate: Function,
		}
		impl $name {
    		pub fn new() -> FIWrap<Self> {
        		FIWrap::new($name { delegate: Function::new() })
    		}
		}
		impl FuncDelegate for $name {
		    fn delegate(&mut self) -> &mut Function {
    		    &mut self.delegate
    		}
		}

	)
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#[macro_export]
macro_rules! g_str {
    ($lit:expr) => {
        $crate::gstr::GStr::from_static_bytes(concat!($lit, "\0").as_bytes())
    }
}

#[macro_export]
macro_rules! g_utf8 {
    ($lit:expr) => {
        $crate::gstr::Utf8::from_static_str(concat!($lit, "\0"))
    }
}

#[macro_export]
macro_rules! g_error_match {
    (
        ($inp:expr) {
            ($slot:ident : $errtype:ty) => $handler:expr,
            $(($slot_tail:ident : $errtype_tail:ty) => $handler_tail:expr,)*
            other $catchall_slot:ident => $catchall_handler:expr
        }
    ) => {
        {
            let err: $crate::error::Error = $inp;
            let res: std::result::Result<$errtype, $crate::error::Error>
                     = err.into_domain();
            match res {
                Ok($slot) => $handler,
                Err(e) => g_error_match! {
                    (e) {
                        $(($slot_tail: $errtype_tail) => $handler_tail,)*
                        other $catchall_slot => $catchall_handler
                    }
                }
            }
        }
    };
    (
        ($inp:expr) {
            other $catchall_slot:ident => $catchall_handler:expr
        }
    ) => {
        {
            let $catchall_slot: $crate::error::Error = $inp;
            $catchall_handler
        }
    }
}

#[macro_export]
macro_rules! g_static_quark {
    ($lit:expr) => {
        {
            use $crate::quark::StaticQuark;

            static QUARK: StaticQuark =
                StaticQuark($lit, std::sync::atomic::ATOMIC_UINT_INIT);

            QUARK.get()
        }
    }
}

#[macro_export]
macro_rules! g_type_register_box {
    ($t:ty, $name:expr) => {
        unsafe impl $crate::boxed::BoxRegistered for $t {
            fn box_type() -> $crate::gtype::GType {
                use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
                use std::sync::atomic::Ordering::{Acquire,Release};
                use std::sync::{Once, ONCE_INIT};

                static REGISTERED: AtomicUsize = ATOMIC_USIZE_INIT;
                static INIT: Once = ONCE_INIT;

                INIT.call_once(|| {
                    let gtype = $crate::boxed::register_box_type::<$t>($name);
                    REGISTERED.store(gtype.to_raw() as usize, Release);
                });

                let raw = REGISTERED.load(Acquire)
                          as $crate::gtype::raw::GType;
                unsafe { $crate::gtype::GType::from_raw(raw) }
            }
        }
    }
}

#[macro_export]
macro_rules! g_impl_boxed_type_for_ref {
    ($t:ty, $get_type:path) => {
        impl $crate::boxed::BoxedType for $crate::refcount::Ref<$t> {

            fn get_type() -> $crate::gtype::GType {
                unsafe { $crate::gtype::GType::from_raw($get_type()) }
            }

            #[inline]
            unsafe fn from_ptr(ptr: $crate::types::gpointer) -> Self {
                let ptr = ptr as *mut <$t as $crate::wrap::Wrapper>::Raw;
                $crate::refcount::Ref::from_raw(ptr)
            }

            #[inline]
            unsafe fn into_ptr(self) -> $crate::types::gpointer {
                $crate::refcount::ref_into_raw(self) as $crate::types::gpointer
            }
        }
    }
}
<commit_msg>macros: Use global paths for std items<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#[macro_export]
macro_rules! g_str {
    ($lit:expr) => {
        $crate::gstr::GStr::from_static_bytes(concat!($lit, "\0").as_bytes())
    }
}

#[macro_export]
macro_rules! g_utf8 {
    ($lit:expr) => {
        $crate::gstr::Utf8::from_static_str(concat!($lit, "\0"))
    }
}

#[macro_export]
macro_rules! g_error_match {
    (
        ($inp:expr) {
            ($slot:ident : $errtype:ty) => $handler:expr,
            $(($slot_tail:ident : $errtype_tail:ty) => $handler_tail:expr,)*
            other $catchall_slot:ident => $catchall_handler:expr
        }
    ) => {
        {
            let err: $crate::error::Error = $inp;
            let res: ::std::result::Result<$errtype, $crate::error::Error>
                     = err.into_domain();
            match res {
                Ok($slot) => $handler,
                Err(e) => g_error_match! {
                    (e) {
                        $(($slot_tail: $errtype_tail) => $handler_tail,)*
                        other $catchall_slot => $catchall_handler
                    }
                }
            }
        }
    };
    (
        ($inp:expr) {
            other $catchall_slot:ident => $catchall_handler:expr
        }
    ) => {
        {
            let $catchall_slot: $crate::error::Error = $inp;
            $catchall_handler
        }
    }
}

#[macro_export]
macro_rules! g_static_quark {
    ($lit:expr) => {
        {
            use $crate::quark::StaticQuark;

            static QUARK: StaticQuark =
                StaticQuark($lit, ::std::sync::atomic::ATOMIC_UINT_INIT);

            QUARK.get()
        }
    }
}

#[macro_export]
macro_rules! g_type_register_box {
    ($t:ty, $name:expr) => {
        unsafe impl $crate::boxed::BoxRegistered for $t {
            fn box_type() -> $crate::gtype::GType {
                use ::std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
                use ::std::sync::atomic::Ordering::{Acquire,Release};
                use ::std::sync::{Once, ONCE_INIT};

                static REGISTERED: AtomicUsize = ATOMIC_USIZE_INIT;
                static INIT: Once = ONCE_INIT;

                INIT.call_once(|| {
                    let gtype = $crate::boxed::register_box_type::<$t>($name);
                    REGISTERED.store(gtype.to_raw() as usize, Release);
                });

                let raw = REGISTERED.load(Acquire)
                          as $crate::gtype::raw::GType;
                unsafe { $crate::gtype::GType::from_raw(raw) }
            }
        }
    }
}

#[macro_export]
macro_rules! g_impl_boxed_type_for_ref {
    ($t:ty, $get_type:path) => {
        impl $crate::boxed::BoxedType for $crate::refcount::Ref<$t> {

            fn get_type() -> $crate::gtype::GType {
                unsafe { $crate::gtype::GType::from_raw($get_type()) }
            }

            #[inline]
            unsafe fn from_ptr(ptr: $crate::types::gpointer) -> Self {
                let ptr = ptr as *mut <$t as $crate::wrap::Wrapper>::Raw;
                $crate::refcount::Ref::from_raw(ptr)
            }

            #[inline]
            unsafe fn into_ptr(self) -> $crate::types::gpointer {
                $crate::refcount::ref_into_raw(self) as $crate::types::gpointer
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! as_item { ($i:item) => {$i} }

// Required because if-let can't be used with irrefutable patterns, so it needs to be special
// cased.
#[macro_export]
macro_rules! request_fns {
    ($fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty) => (
        pub fn $fn_name(&self, $($arg: $in_),*) -> Result<$out> {
            let reply = try!((self.0).rpc(&request_variant!($fn_name $($arg),*)));
            let Reply::$fn_name(reply) = reply;
            Ok(reply)
        }
    );
    ($( $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty)*) => ( $(
        pub fn $fn_name(&self, $($arg: $in_),*) -> Result<$out> {
            let reply = try!((self.0).rpc(&request_variant!($fn_name $($arg),*)));
            if let Reply::$fn_name(reply) = reply {
                Ok(reply)
            } else {
                Err(Error::InternalError)
            }
        }
    )*);
}

// Required because enum variants with no fields can't be suffixed by parens
#[macro_export]
macro_rules! define_request {
    ($(@($($finished:tt)*))* --) => (as_item!(
            #[allow(non_camel_case_types)]
            #[derive(Debug, Serialize, Deserialize)]
            enum Request { $($($finished)*),* }
    ););
    ($(@$finished:tt)* -- $name:ident() $($req:tt)*) =>
        (define_request!($(@$finished)* @($name) -- $($req)*););
    ($(@$finished:tt)* -- $name:ident $args: tt $($req:tt)*) =>
        (define_request!($(@$finished)* @($name $args) -- $($req)*););
    ($($started:tt)*) => (define_request!(-- $($started)*););
}

// Required because enum variants with no fields can't be suffixed by parens
#[macro_export]
macro_rules! request_variant {
    ($x:ident) => (Request::$x);
    ($x:ident $($y:ident),+) => (Request::$x($($y),+));
}

// The main macro that creates RPC services.
#[macro_export]
macro_rules! rpc_service { ($server:ident:
    $( $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;)*) => {
        #[allow(dead_code)]
        pub mod $server {
            use std::net::ToSocketAddrs;
            use std::io;
            use std::sync::Arc;
            use $crate::protocol::{
                self,
                ServeHandle,
                serve_async,
            };

            #[doc="An RPC error that occurred during serving an RPC request."]
            #[derive(Debug)]
            pub enum Error {
                #[doc="An IO error occurred."]
                Io(io::Error),

                #[doc="An unexpected internal error. Typically a bug in the server impl."]
                InternalError,
            }

            impl ::std::convert::From<protocol::Error> for Error {
                fn from(err: protocol::Error) -> Error {
                    match err {
                        protocol::Error::Io(err) => Error::Io(err),
                        _ => Error::InternalError,
                    }
                }
            }

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

            #[doc="The result of an RPC call; either the successful result or the error."]
            pub type Result<T> = ::std::result::Result<T, Error>;

            #[doc="The provided RPC service."]
            pub trait Service: Send + Sync {
                $(
                    fn $fn_name(&self, $($arg:$in_),*) -> $out;
                )*
            }

            define_request!($($fn_name($($in_),*))*);

            #[allow(non_camel_case_types)]
            #[derive(Debug, Serialize, Deserialize)]
            enum Reply {
                $(
                    $fn_name($out),
                )*
            }

            #[doc="The client stub that makes RPC calls to the server."]
            pub struct Client(protocol::Client<Request, Reply>);

            impl Client {
                #[doc="Create a new client that connects to the given address."]
                pub fn new<A>(addr: A) -> Result<Self>
                    where A: ToSocketAddrs,
                {
                    let inner = try!(protocol::Client::new(addr));
                    Ok(Client(inner))
                }

                request_fns!($($fn_name($($arg: $in_),*) -> $out)*);
            }

            struct Server<S: 'static + Service>(S);

            impl<S> protocol::Serve<Request, Reply> for Server<S>
                where S: 'static + Service
            {
                fn serve(&self, request: Request) -> Reply {
                    match request {
                        $(
                            request_variant!($fn_name $($arg),*) =>
                                Reply::$fn_name((self.0).$fn_name($($arg),*)),
                         )*
                    }
                }
            }

            #[doc="Start a running service."]
            pub fn serve<A, S>(addr: A, service: S) -> Result<ServeHandle>
                where A: ToSocketAddrs,
                      S: 'static + Service
            {
                let server = Arc::new(Server(service));
                Ok(try!(serve_async(addr, server)))
            }
        }
    }
}

#[cfg(test)]
mod test {

    rpc_service!(my_server:
        hello(foo: super::Foo) -> super::Foo;

        add(x: i32, y: i32) -> i32;
    );

    use self::my_server::*;

    #[derive(PartialEq, Debug, Serialize, Deserialize)]
    pub struct Foo {
        message: String
    }

    impl Service for () {
        fn hello(&self, s: Foo) -> Foo {
            Foo{message: format!("Hello, {}", &s.message)}
        }

        fn add(&self, x: i32, y: i32) -> i32 {
            x + y
        }
    }

    #[test]
    fn simple_test() {
        println!("Starting");
        let addr = "127.0.0.1:9000";
        let shutdown = my_server::serve(addr, ()).unwrap();
        let client = Client::new(addr).unwrap();
        assert_eq!(3, client.add(1, 2).unwrap());
        let foo = Foo{message: "Adam".into()};
        let want = Foo{message: format!("Hello, {}", &foo.message)};
        assert_eq!(want, client.hello(Foo{message: "Adam".into()}).unwrap());
        drop(client);
        shutdown.shutdown();
    }

    // This is a test of a service with a fn that takes no args
    rpc_service! {foo:
        hello() -> String;
    }
}
<commit_msg>Add doc comment to generated module<commit_after>#[macro_export]
macro_rules! as_item { ($i:item) => {$i} }

// Required because if-let can't be used with irrefutable patterns, so it needs to be special
// cased.
#[macro_export]
macro_rules! request_fns {
    ($fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty) => (
        pub fn $fn_name(&self, $($arg: $in_),*) -> Result<$out> {
            let reply = try!((self.0).rpc(&request_variant!($fn_name $($arg),*)));
            let Reply::$fn_name(reply) = reply;
            Ok(reply)
        }
    );
    ($( $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty)*) => ( $(
        pub fn $fn_name(&self, $($arg: $in_),*) -> Result<$out> {
            let reply = try!((self.0).rpc(&request_variant!($fn_name $($arg),*)));
            if let Reply::$fn_name(reply) = reply {
                Ok(reply)
            } else {
                Err(Error::InternalError)
            }
        }
    )*);
}

// Required because enum variants with no fields can't be suffixed by parens
#[macro_export]
macro_rules! define_request {
    ($(@($($finished:tt)*))* --) => (as_item!(
            #[allow(non_camel_case_types)]
            #[derive(Debug, Serialize, Deserialize)]
            enum Request { $($($finished)*),* }
    ););
    ($(@$finished:tt)* -- $name:ident() $($req:tt)*) =>
        (define_request!($(@$finished)* @($name) -- $($req)*););
    ($(@$finished:tt)* -- $name:ident $args: tt $($req:tt)*) =>
        (define_request!($(@$finished)* @($name $args) -- $($req)*););
    ($($started:tt)*) => (define_request!(-- $($started)*););
}

// Required because enum variants with no fields can't be suffixed by parens
#[macro_export]
macro_rules! request_variant {
    ($x:ident) => (Request::$x);
    ($x:ident $($y:ident),+) => (Request::$x($($y),+));
}

// The main macro that creates RPC services.
#[macro_export]
macro_rules! rpc_service { ($server:ident:
    $( $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;)*) => {
        #[doc="A module containing an rpc service and client stub."]
        pub mod $server {
            use std::net::ToSocketAddrs;
            use std::io;
            use std::sync::Arc;
            use $crate::protocol::{
                self,
                ServeHandle,
                serve_async,
            };

            #[doc="An RPC error that occurred during serving an RPC request."]
            #[derive(Debug)]
            pub enum Error {
                #[doc="An IO error occurred."]
                Io(io::Error),

                #[doc="An unexpected internal error. Typically a bug in the server impl."]
                InternalError,
            }

            impl ::std::convert::From<protocol::Error> for Error {
                fn from(err: protocol::Error) -> Error {
                    match err {
                        protocol::Error::Io(err) => Error::Io(err),
                        _ => Error::InternalError,
                    }
                }
            }

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

            #[doc="The result of an RPC call; either the successful result or the error."]
            pub type Result<T> = ::std::result::Result<T, Error>;

            #[doc="The provided RPC service."]
            pub trait Service: Send + Sync {
                $(
                    fn $fn_name(&self, $($arg:$in_),*) -> $out;
                )*
            }

            define_request!($($fn_name($($in_),*))*);

            #[allow(non_camel_case_types)]
            #[derive(Debug, Serialize, Deserialize)]
            enum Reply {
                $(
                    $fn_name($out),
                )*
            }

            #[doc="The client stub that makes RPC calls to the server."]
            pub struct Client(protocol::Client<Request, Reply>);

            impl Client {
                #[doc="Create a new client that connects to the given address."]
                pub fn new<A>(addr: A) -> Result<Self>
                    where A: ToSocketAddrs,
                {
                    let inner = try!(protocol::Client::new(addr));
                    Ok(Client(inner))
                }

                request_fns!($($fn_name($($arg: $in_),*) -> $out)*);
            }

            struct Server<S: 'static + Service>(S);

            impl<S> protocol::Serve<Request, Reply> for Server<S>
                where S: 'static + Service
            {
                fn serve(&self, request: Request) -> Reply {
                    match request {
                        $(
                            request_variant!($fn_name $($arg),*) =>
                                Reply::$fn_name((self.0).$fn_name($($arg),*)),
                         )*
                    }
                }
            }

            #[doc="Start a running service."]
            pub fn serve<A, S>(addr: A, service: S) -> Result<ServeHandle>
                where A: ToSocketAddrs,
                      S: 'static + Service
            {
                let server = Arc::new(Server(service));
                Ok(try!(serve_async(addr, server)))
            }
        }
    }
}

#[cfg(test)]
#[allow(dead_code)]
mod test {

    rpc_service!(my_server:
        hello(foo: super::Foo) -> super::Foo;

        add(x: i32, y: i32) -> i32;
    );

    use self::my_server::*;

    #[derive(PartialEq, Debug, Serialize, Deserialize)]
    pub struct Foo {
        message: String
    }

    impl Service for () {
        fn hello(&self, s: Foo) -> Foo {
            Foo{message: format!("Hello, {}", &s.message)}
        }

        fn add(&self, x: i32, y: i32) -> i32 {
            x + y
        }
    }

    #[test]
    fn simple_test() {
        println!("Starting");
        let addr = "127.0.0.1:9000";
        let shutdown = my_server::serve(addr, ()).unwrap();
        let client = Client::new(addr).unwrap();
        assert_eq!(3, client.add(1, 2).unwrap());
        let foo = Foo{message: "Adam".into()};
        let want = Foo{message: format!("Hello, {}", &foo.message)};
        assert_eq!(want, client.hello(Foo{message: "Adam".into()}).unwrap());
        drop(client);
        shutdown.shutdown();
    }

    // This is a test of a service with a fn that takes no args
    rpc_service! {foo:
        hello() -> String;
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "serde")]

use hashbrown::{HashMap, HashSet};
use serde_test::{assert_tokens, Token};

#[test]
fn map_serde_tokens_empty() {
    let map = HashMap::<char, u32>::new();

    assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]);
}

#[test]
fn map_serde_tokens() {
    let mut map = HashMap::new();
    map.insert('b', 20);
    map.insert('a', 10);
    map.insert('c', 30);

    assert_tokens(
        &map,
        &[
            Token::Map { len: Some(3) },
            Token::Char('a'),
            Token::I32(10),
            Token::Char('b'),
            Token::I32(20),
            Token::Char('c'),
            Token::I32(30),
            Token::MapEnd,
        ],
    );
}

#[test]
fn set_serde_tokens_empty() {
    let set = HashSet::<u32>::new();

    assert_tokens(&set, &[Token::Seq { len: Some(0) }, Token::SeqEnd]);
}

#[test]
fn set_serde_tokens() {
    let mut set = HashSet::new();
    set.insert(20);
    set.insert(10);
    set.insert(30);

    assert_tokens(
        &set,
        &[
            Token::Seq { len: Some(3) },
            Token::I32(20),
            Token::I32(10),
            Token::I32(30),
            Token::SeqEnd,
        ],
    );
}
<commit_msg>Use FxHash for serde test<commit_after>#![cfg(feature = "serde")]

use hashbrown::{HashMap, HashSet};
use serde_test::{assert_tokens, Token};
use rustc_hash::FxHasher;
use core::hash::BuildHasherDefault;

// We use FxHash for this test because we rely on the ordering
type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
type FxHashSet<T> = HashSet<T, BuildHasherDefault<FxHasher>>;

#[test]
fn map_serde_tokens_empty() {
    let map = FxHashMap::<char, u32>::default();

    assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]);
}

#[test]
fn map_serde_tokens() {
    let mut map = FxHashMap::default();
    map.insert('b', 20);
    map.insert('a', 10);
    map.insert('c', 30);

    assert_tokens(
        &map,
        &[
            Token::Map { len: Some(3) },
            Token::Char('a'),
            Token::I32(10),
            Token::Char('b'),
            Token::I32(20),
            Token::Char('c'),
            Token::I32(30),
            Token::MapEnd,
        ],
    );
}

#[test]
fn set_serde_tokens_empty() {
    let set = FxHashSet::<u32>::default();

    assert_tokens(&set, &[Token::Seq { len: Some(0) }, Token::SeqEnd]);
}

#[test]
fn set_serde_tokens() {
    let mut set = FxHashSet::default();
    set.insert(20);
    set.insert(10);
    set.insert(30);

    assert_tokens(
        &set,
        &[
            Token::Seq { len: Some(3) },
            Token::I32(20),
            Token::I32(10),
            Token::I32(30),
            Token::SeqEnd,
        ],
    );
}
<|endoftext|>