<commit_before>use crate::core::InvertedIndexReader;
use crate::core::Segment;
use crate::core::SegmentComponent;
use crate::core::SegmentId;
use crate::directory::FileSlice;
use crate::fastfield::DeleteBitSet;
use crate::fastfield::FacetReader;
use crate::fastfield::FastFieldReaders;
use crate::fieldnorm::{FieldNormReader, FieldNormReaders};
use crate::schema::FieldType;
use crate::schema::Schema;
use crate::schema::{Field, IndexRecordOption};
use crate::space_usage::SegmentSpaceUsage;
use crate::store::StoreReader;
use crate::termdict::TermDictionary;
use crate::DocId;
use crate::{common::CompositeFile, error::DataCorruption};
use fail::fail_point;
use std::fmt;
use std::sync::Arc;
use std::sync::RwLock;
use std::{collections::HashMap, io};

/// Entry point to access all of the datastructures of the `Segment`
///
/// - term dictionary
/// - postings
/// - store
/// - fast field readers
/// - field norm reader
///
/// The segment reader has a very low memory footprint,
/// as close to all of the memory data is mmapped.
///
///
/// TODO fix not decoding docfreq
#[derive(Clone)]
pub struct SegmentReader {
    inv_idx_reader_cache: Arc<RwLock<HashMap<Field, Arc<InvertedIndexReader>>>>,

    segment_id: SegmentId,
    max_doc: DocId,
    num_docs: DocId,

    termdict_composite: CompositeFile,
    postings_composite: CompositeFile,
    positions_composite: CompositeFile,
    fast_fields_readers: Arc<FastFieldReaders>,
    fieldnorm_readers: FieldNormReaders,

    store_file: FileSlice,
    delete_bitset_opt: Option<DeleteBitSet>,
    schema: Schema,
}

impl SegmentReader {
    /// Returns the highest document id ever attributed in
    /// this segment + 1.
    /// Today, `tantivy` does not handle deletes, so it happens
    /// to also be the number of documents in the index.
    pub fn max_doc(&self) -> DocId {
        self.max_doc
    }

    /// Returns the number of alive documents.
    /// Deleted documents are not counted.
    ///
    pub fn num_docs(&self) -> DocId {
        self.num_docs
    }

    /// Returns the schema of the index this segment belongs to.
    pub fn schema(&self) -> &Schema {
        &self.schema
    }

    /// Return the number of documents that have been
    /// deleted in the segment.
    pub fn num_deleted_docs(&self) -> DocId {
        self.delete_bitset()
            .map(|delete_set| delete_set.num_deleted() as DocId)
            .unwrap_or(0u32)
    }

    /// Returns true iff some of the documents of the segment have been deleted.
    pub fn has_deletes(&self) -> bool {
        self.delete_bitset().is_some()
    }

    /// Accessor to a segment's fast field reader given a field.
    ///
    /// Returns the u64 fast value reader if the field
    /// is a u64 field indexed as "fast".
    ///
    /// Return a FastFieldNotAvailableError if the field is not
    /// declared as a fast field in the schema.
    ///
    /// # Panics
    /// May panic if the index is corrupted.
    pub fn fast_fields(&self) -> &FastFieldReaders {
        &self.fast_fields_readers
    }

    /// Accessor to the `FacetReader` associated to a given `Field`.
    pub fn facet_reader(&self, field: Field) -> crate::Result<FacetReader> {
        let field_entry = self.schema.get_field_entry(field);

        match field_entry.field_type() {
            FieldType::HierarchicalFacet(_) => {
                let term_ords_reader = self.fast_fields().u64s(field)?;
                let termdict = self
                    .termdict_composite
                    .open_read(field)
                    .map(TermDictionary::open)
                    .unwrap_or_else(|| Ok(TermDictionary::empty()))?;
                Ok(FacetReader::new(term_ords_reader, termdict))
            }
            _ => Err(crate::TantivyError::InvalidArgument(format!(
                "Field {:?} is not a facet field.",
                field_entry.name()
            ))),
        }
    }

    /// Accessor to the segment's `Field norms`'s reader.
    ///
    /// Field norms are the length (in tokens) of the fields.
    /// It is used in the computation of the [TfIdf](https://fulmicoton.gitbooks.io/tantivy-doc/content/tfidf.html).
    ///
    /// They are simply stored as a fast field, serialized in
    /// the `.fieldnorm` file of the segment.
    pub fn get_fieldnorms_reader(&self, field: Field) -> crate::Result<FieldNormReader> {
        self.fieldnorm_readers.get_field(field)?.ok_or_else(|| {
            let field_name = self.schema.get_field_name(field);
            let err_msg = format!(
                "Field norm not found for field {:?}. Was it marked as indexed during indexing?",
                field_name
            );
            crate::TantivyError::SchemaError(err_msg)
        })
    }

    /// Accessor to the segment's `StoreReader`.
    pub fn get_store_reader(&self) -> io::Result<StoreReader> {
        StoreReader::open(self.store_file.clone())
    }

    /// Open a new segment for reading.
    pub fn open(segment: &Segment) -> crate::Result<SegmentReader> {
        let termdict_file = segment.open_read(SegmentComponent::Terms)?;
        let termdict_composite = CompositeFile::open(&termdict_file)?;

        let store_file = segment.open_read(SegmentComponent::Store)?;

        fail_point!("SegmentReader::open#middle");

        let postings_file = segment.open_read(SegmentComponent::Postings)?;
        let postings_composite = CompositeFile::open(&postings_file)?;

        let positions_composite = {
            if let Ok(positions_file) = segment.open_read(SegmentComponent::Positions) {
                CompositeFile::open(&positions_file)?
            } else {
                CompositeFile::empty()
            }
        };

        let schema = segment.schema();

        let fast_fields_data = segment.open_read(SegmentComponent::FastFields)?;
        let fast_fields_composite = CompositeFile::open(&fast_fields_data)?;
        let fast_field_readers =
            Arc::new(FastFieldReaders::new(schema.clone(), fast_fields_composite));

        let fieldnorm_data = segment.open_read(SegmentComponent::FieldNorms)?;
        let fieldnorm_readers = FieldNormReaders::open(fieldnorm_data)?;

        let delete_bitset_opt = if segment.meta().has_deletes() {
            let delete_data = segment.open_read(SegmentComponent::Delete)?;
            let delete_bitset = DeleteBitSet::open(delete_data)?;
            Some(delete_bitset)
        } else {
            None
        };

        Ok(SegmentReader {
            inv_idx_reader_cache: Default::default(),
            max_doc: segment.meta().max_doc(),
            num_docs: segment.meta().num_docs(),
            termdict_composite,
            postings_composite,
            fast_fields_readers: fast_field_readers,
            fieldnorm_readers,
            segment_id: segment.id(),
            store_file,
            delete_bitset_opt,
            positions_composite,
            schema,
        })
    }

    /// Returns a field reader associated to the field given in argument.
    /// If the field was not present in the index during indexing time,
    /// the InvertedIndexReader is empty.
    ///
    /// The field reader is in charge of iterating through the
    /// term dictionary associated to a specific field,
    /// and opening the posting list associated to any term.
    ///
    /// If the field is marked as index, a warn is logged and an empty `InvertedIndexReader`
    /// is returned.
    /// Similarly if the field is marked as indexed but no term has been indexed for the given
    /// index. an empty `InvertedIndexReader` is returned (but no warning is logged).
    pub fn inverted_index(&self, field: Field) -> crate::Result<Arc<InvertedIndexReader>> {
        if let Some(inv_idx_reader) = self
            .inv_idx_reader_cache
            .read()
            .expect("Lock poisoned. This should never happen")
            .get(&field)
        {
            return Ok(Arc::clone(inv_idx_reader));
        }
        let field_entry = self.schema.get_field_entry(field);
        let field_type = field_entry.field_type();
        let record_option_opt = field_type.get_index_record_option();

        if record_option_opt.is_none() {
            warn!("Field {:?} does not seem indexed.", field_entry.name());
        }

        let postings_file_opt = self.postings_composite.open_read(field);

        if postings_file_opt.is_none() || record_option_opt.is_none() {
            // no documents in the segment contained this field.
            // As a result, no data is associated to the inverted index.
            //
            // Returns an empty inverted index.
            let record_option = record_option_opt.unwrap_or(IndexRecordOption::Basic);
            return Ok(Arc::new(InvertedIndexReader::empty(record_option)));
        }

        let record_option = record_option_opt.unwrap();
        let postings_file = postings_file_opt.unwrap();

        let termdict_file: FileSlice = self.termdict_composite.open_read(field)
            .ok_or_else(||
               DataCorruption::comment_only(format!("Failed to open field {:?}'s term dictionary in the composite file. Has the schema been modified?", field_entry.name()))
            )?;

        let positions_file = self
            .positions_composite
            .open_read(field)
            .ok_or_else(|| {
                let error_msg = format!("Failed to open field {:?}'s positions in the composite file. Has the schema been modified?", field_entry.name());
               DataCorruption::comment_only(error_msg)
            })?;

        let inv_idx_reader = Arc::new(InvertedIndexReader::new(
            TermDictionary::open(termdict_file)?,
            postings_file,
            positions_file,
            record_option,
        )?);

        // by releasing the lock in between, we may end up opening the inverting index
        // twice, but this is fine.
        self.inv_idx_reader_cache
            .write()
            .expect("Field reader cache lock poisoned. This should never happen.")
            .insert(field, Arc::clone(&inv_idx_reader));

        Ok(inv_idx_reader)
    }

    /// Returns the segment id
    pub fn segment_id(&self) -> SegmentId {
        self.segment_id
    }

    /// Returns the bitset representing
    /// the documents that have been deleted.
    pub fn delete_bitset(&self) -> Option<&DeleteBitSet> {
        self.delete_bitset_opt.as_ref()
    }

    /// Returns true iff the `doc` is marked
    /// as deleted.
    pub fn is_deleted(&self, doc: DocId) -> bool {
        self.delete_bitset()
            .map(|delete_set| delete_set.is_deleted(doc))
            .unwrap_or(false)
    }

    /// Returns an iterator that will iterate over the alive document ids
    pub fn doc_ids_alive(&self) -> impl Iterator<Item = DocId> + '_ {
        (0u32..self.max_doc).filter(move |doc| !self.is_deleted(*doc))
    }

    /// Summarize total space usage of this segment.
    pub fn space_usage(&self) -> io::Result<SegmentSpaceUsage> {
        Ok(SegmentSpaceUsage::new(
            self.num_docs(),
            self.termdict_composite.space_usage(),
            self.postings_composite.space_usage(),
            self.positions_composite.space_usage(),
            self.fast_fields_readers.space_usage(),
            self.fieldnorm_readers.space_usage(),
            self.get_store_reader()?.space_usage(),
            self.delete_bitset_opt
                .as_ref()
                .map(DeleteBitSet::space_usage)
                .unwrap_or(0),
        ))
    }
}

impl fmt::Debug for SegmentReader {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "SegmentReader({:?})", self.segment_id)
    }
}

#[cfg(test)]
mod test {
    use crate::core::Index;
    use crate::schema::{Schema, Term, STORED, TEXT};
    use crate::DocId;

    #[test]
    fn test_num_alive() -> crate::Result<()> {
        let mut schema_builder = Schema::builder();
        schema_builder.add_text_field("name", TEXT | STORED);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema.clone());
        let name = schema.get_field("name").unwrap();

        {
            let mut index_writer = index.writer_for_tests()?;
            index_writer.add_document(doc!(name => "tantivy"));
            index_writer.add_document(doc!(name => "horse"));
            index_writer.add_document(doc!(name => "jockey"));
            index_writer.add_document(doc!(name => "cap"));
            // we should now have one segment with two docs
            index_writer.delete_term(Term::from_field_text(name, "horse"));
            index_writer.delete_term(Term::from_field_text(name, "cap"));

            // ok, now we should have a deleted doc
            index_writer.commit()?;
        }
        let searcher = index.reader()?.searcher();
        assert_eq!(2, searcher.segment_reader(0).num_docs());
        assert_eq!(4, searcher.segment_reader(0).max_doc());
        Ok(())
    }
    #[test]
    fn test_alive_docs_iterator() -> crate::Result<()> {
        let mut schema_builder = Schema::builder();
        schema_builder.add_text_field("name", TEXT | STORED);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema.clone());
        let name = schema.get_field("name").unwrap();

        {
            let mut index_writer = index.writer_for_tests()?;
            index_writer.add_document(doc!(name => "tantivy"));
            index_writer.add_document(doc!(name => "horse"));
            index_writer.add_document(doc!(name => "jockey"));
            index_writer.add_document(doc!(name => "cap"));
            // we should now have one segment with two docs
            index_writer.commit()?;
        }

        {
            let mut index_writer2 = index.writer(50_000_000)?;
            index_writer2.delete_term(Term::from_field_text(name, "horse"));
            index_writer2.delete_term(Term::from_field_text(name, "cap"));

            // ok, now we should have a deleted doc
            index_writer2.commit()?;
        }
        let searcher = index.reader()?.searcher();
        let docs: Vec<DocId> = searcher.segment_reader(0).doc_ids_alive().collect();
        assert_eq!(vec![0u32, 2u32], docs);
        Ok(())
    }
}
<commit_msg>stale comments in segment_reader.rs<commit_after>use crate::core::InvertedIndexReader;
use crate::core::Segment;
use crate::core::SegmentComponent;
use crate::core::SegmentId;
use crate::directory::FileSlice;
use crate::fastfield::DeleteBitSet;
use crate::fastfield::FacetReader;
use crate::fastfield::FastFieldReaders;
use crate::fieldnorm::{FieldNormReader, FieldNormReaders};
use crate::schema::FieldType;
use crate::schema::Schema;
use crate::schema::{Field, IndexRecordOption};
use crate::space_usage::SegmentSpaceUsage;
use crate::store::StoreReader;
use crate::termdict::TermDictionary;
use crate::DocId;
use crate::{common::CompositeFile, error::DataCorruption};
use fail::fail_point;
use std::fmt;
use std::sync::Arc;
use std::sync::RwLock;
use std::{collections::HashMap, io};

/// Entry point to access all of the datastructures of the `Segment`
///
/// - term dictionary
/// - postings
/// - store
/// - fast field readers
/// - field norm reader
///
/// The segment reader has a very low memory footprint,
/// as close to all of the memory data is mmapped.
#[derive(Clone)]
pub struct SegmentReader {
    inv_idx_reader_cache: Arc<RwLock<HashMap<Field, Arc<InvertedIndexReader>>>>,

    segment_id: SegmentId,
    max_doc: DocId,
    num_docs: DocId,

    termdict_composite: CompositeFile,
    postings_composite: CompositeFile,
    positions_composite: CompositeFile,
    fast_fields_readers: Arc<FastFieldReaders>,
    fieldnorm_readers: FieldNormReaders,

    store_file: FileSlice,
    delete_bitset_opt: Option<DeleteBitSet>,
    schema: Schema,
}

impl SegmentReader {
    /// Returns the highest document id ever attributed in
    /// this segment + 1.
    pub fn max_doc(&self) -> DocId {
        self.max_doc
    }

    /// Returns the number of alive documents.
    /// Deleted documents are not counted.
    pub fn num_docs(&self) -> DocId {
        self.num_docs
    }

    /// Returns the schema of the index this segment belongs to.
    pub fn schema(&self) -> &Schema {
        &self.schema
    }

    /// Return the number of documents that have been
    /// deleted in the segment.
    pub fn num_deleted_docs(&self) -> DocId {
        self.delete_bitset()
            .map(|delete_set| delete_set.num_deleted() as DocId)
            .unwrap_or(0u32)
    }

    /// Returns true iff some of the documents of the segment have been deleted.
    pub fn has_deletes(&self) -> bool {
        self.delete_bitset().is_some()
    }

    /// Accessor to a segment's fast field reader given a field.
    ///
    /// Returns the u64 fast value reader if the field
    /// is a u64 field indexed as "fast".
    ///
    /// Return a FastFieldNotAvailableError if the field is not
    /// declared as a fast field in the schema.
    ///
    /// # Panics
    /// May panic if the index is corrupted.
    pub fn fast_fields(&self) -> &FastFieldReaders {
        &self.fast_fields_readers
    }

    /// Accessor to the `FacetReader` associated to a given `Field`.
    pub fn facet_reader(&self, field: Field) -> crate::Result<FacetReader> {
        let field_entry = self.schema.get_field_entry(field);

        match field_entry.field_type() {
            FieldType::HierarchicalFacet(_) => {
                let term_ords_reader = self.fast_fields().u64s(field)?;
                let termdict = self
                    .termdict_composite
                    .open_read(field)
                    .map(TermDictionary::open)
                    .unwrap_or_else(|| Ok(TermDictionary::empty()))?;
                Ok(FacetReader::new(term_ords_reader, termdict))
            }
            _ => Err(crate::TantivyError::InvalidArgument(format!(
                "Field {:?} is not a facet field.",
                field_entry.name()
            ))),
        }
    }

    /// Accessor to the segment's `Field norms`'s reader.
    ///
    /// Field norms are the length (in tokens) of the fields.
    /// It is used in the computation of the [TfIdf](https://fulmicoton.gitbooks.io/tantivy-doc/content/tfidf.html).
    ///
    /// They are simply stored as a fast field, serialized in
    /// the `.fieldnorm` file of the segment.
    pub fn get_fieldnorms_reader(&self, field: Field) -> crate::Result<FieldNormReader> {
        self.fieldnorm_readers.get_field(field)?.ok_or_else(|| {
            let field_name = self.schema.get_field_name(field);
            let err_msg = format!(
                "Field norm not found for field {:?}. Was it marked as indexed during indexing?",
                field_name
            );
            crate::TantivyError::SchemaError(err_msg)
        })
    }

    /// Accessor to the segment's `StoreReader`.
    pub fn get_store_reader(&self) -> io::Result<StoreReader> {
        StoreReader::open(self.store_file.clone())
    }

    /// Open a new segment for reading.
    pub fn open(segment: &Segment) -> crate::Result<SegmentReader> {
        let termdict_file = segment.open_read(SegmentComponent::Terms)?;
        let termdict_composite = CompositeFile::open(&termdict_file)?;

        let store_file = segment.open_read(SegmentComponent::Store)?;

        fail_point!("SegmentReader::open#middle");

        let postings_file = segment.open_read(SegmentComponent::Postings)?;
        let postings_composite = CompositeFile::open(&postings_file)?;

        let positions_composite = {
            if let Ok(positions_file) = segment.open_read(SegmentComponent::Positions) {
                CompositeFile::open(&positions_file)?
            } else {
                CompositeFile::empty()
            }
        };

        let schema = segment.schema();

        let fast_fields_data = segment.open_read(SegmentComponent::FastFields)?;
        let fast_fields_composite = CompositeFile::open(&fast_fields_data)?;
        let fast_field_readers =
            Arc::new(FastFieldReaders::new(schema.clone(), fast_fields_composite));

        let fieldnorm_data = segment.open_read(SegmentComponent::FieldNorms)?;
        let fieldnorm_readers = FieldNormReaders::open(fieldnorm_data)?;

        let delete_bitset_opt = if segment.meta().has_deletes() {
            let delete_data = segment.open_read(SegmentComponent::Delete)?;
            let delete_bitset = DeleteBitSet::open(delete_data)?;
            Some(delete_bitset)
        } else {
            None
        };

        Ok(SegmentReader {
            inv_idx_reader_cache: Default::default(),
            max_doc: segment.meta().max_doc(),
            num_docs: segment.meta().num_docs(),
            termdict_composite,
            postings_composite,
            fast_fields_readers: fast_field_readers,
            fieldnorm_readers,
            segment_id: segment.id(),
            store_file,
            delete_bitset_opt,
            positions_composite,
            schema,
        })
    }

    /// Returns a field reader associated to the field given in argument.
    /// If the field was not present in the index during indexing time,
    /// the InvertedIndexReader is empty.
    ///
    /// The field reader is in charge of iterating through the
    /// term dictionary associated to a specific field,
    /// and opening the posting list associated to any term.
    ///
    /// If the field is marked as index, a warn is logged and an empty `InvertedIndexReader`
    /// is returned.
    /// Similarly if the field is marked as indexed but no term has been indexed for the given
    /// index. an empty `InvertedIndexReader` is returned (but no warning is logged).
    pub fn inverted_index(&self, field: Field) -> crate::Result<Arc<InvertedIndexReader>> {
        if let Some(inv_idx_reader) = self
            .inv_idx_reader_cache
            .read()
            .expect("Lock poisoned. This should never happen")
            .get(&field)
        {
            return Ok(Arc::clone(inv_idx_reader));
        }
        let field_entry = self.schema.get_field_entry(field);
        let field_type = field_entry.field_type();
        let record_option_opt = field_type.get_index_record_option();

        if record_option_opt.is_none() {
            warn!("Field {:?} does not seem indexed.", field_entry.name());
        }

        let postings_file_opt = self.postings_composite.open_read(field);

        if postings_file_opt.is_none() || record_option_opt.is_none() {
            // no documents in the segment contained this field.
            // As a result, no data is associated to the inverted index.
            //
            // Returns an empty inverted index.
            let record_option = record_option_opt.unwrap_or(IndexRecordOption::Basic);
            return Ok(Arc::new(InvertedIndexReader::empty(record_option)));
        }

        let record_option = record_option_opt.unwrap();
        let postings_file = postings_file_opt.unwrap();

        let termdict_file: FileSlice = self.termdict_composite.open_read(field)
            .ok_or_else(||
               DataCorruption::comment_only(format!("Failed to open field {:?}'s term dictionary in the composite file. Has the schema been modified?", field_entry.name()))
            )?;

        let positions_file = self
            .positions_composite
            .open_read(field)
            .ok_or_else(|| {
                let error_msg = format!("Failed to open field {:?}'s positions in the composite file. Has the schema been modified?", field_entry.name());
               DataCorruption::comment_only(error_msg)
            })?;

        let inv_idx_reader = Arc::new(InvertedIndexReader::new(
            TermDictionary::open(termdict_file)?,
            postings_file,
            positions_file,
            record_option,
        )?);

        // by releasing the lock in between, we may end up opening the inverting index
        // twice, but this is fine.
        self.inv_idx_reader_cache
            .write()
            .expect("Field reader cache lock poisoned. This should never happen.")
            .insert(field, Arc::clone(&inv_idx_reader));

        Ok(inv_idx_reader)
    }

    /// Returns the segment id
    pub fn segment_id(&self) -> SegmentId {
        self.segment_id
    }

    /// Returns the bitset representing
    /// the documents that have been deleted.
    pub fn delete_bitset(&self) -> Option<&DeleteBitSet> {
        self.delete_bitset_opt.as_ref()
    }

    /// Returns true iff the `doc` is marked
    /// as deleted.
    pub fn is_deleted(&self, doc: DocId) -> bool {
        self.delete_bitset()
            .map(|delete_set| delete_set.is_deleted(doc))
            .unwrap_or(false)
    }

    /// Returns an iterator that will iterate over the alive document ids
    pub fn doc_ids_alive(&self) -> impl Iterator<Item = DocId> + '_ {
        (0u32..self.max_doc).filter(move |doc| !self.is_deleted(*doc))
    }

    /// Summarize total space usage of this segment.
    pub fn space_usage(&self) -> io::Result<SegmentSpaceUsage> {
        Ok(SegmentSpaceUsage::new(
            self.num_docs(),
            self.termdict_composite.space_usage(),
            self.postings_composite.space_usage(),
            self.positions_composite.space_usage(),
            self.fast_fields_readers.space_usage(),
            self.fieldnorm_readers.space_usage(),
            self.get_store_reader()?.space_usage(),
            self.delete_bitset_opt
                .as_ref()
                .map(DeleteBitSet::space_usage)
                .unwrap_or(0),
        ))
    }
}

impl fmt::Debug for SegmentReader {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "SegmentReader({:?})", self.segment_id)
    }
}

#[cfg(test)]
mod test {
    use crate::core::Index;
    use crate::schema::{Schema, Term, STORED, TEXT};
    use crate::DocId;

    #[test]
    fn test_num_alive() -> crate::Result<()> {
        let mut schema_builder = Schema::builder();
        schema_builder.add_text_field("name", TEXT | STORED);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema.clone());
        let name = schema.get_field("name").unwrap();

        {
            let mut index_writer = index.writer_for_tests()?;
            index_writer.add_document(doc!(name => "tantivy"));
            index_writer.add_document(doc!(name => "horse"));
            index_writer.add_document(doc!(name => "jockey"));
            index_writer.add_document(doc!(name => "cap"));
            // we should now have one segment with two docs
            index_writer.delete_term(Term::from_field_text(name, "horse"));
            index_writer.delete_term(Term::from_field_text(name, "cap"));

            // ok, now we should have a deleted doc
            index_writer.commit()?;
        }
        let searcher = index.reader()?.searcher();
        assert_eq!(2, searcher.segment_reader(0).num_docs());
        assert_eq!(4, searcher.segment_reader(0).max_doc());
        Ok(())
    }
    #[test]
    fn test_alive_docs_iterator() -> crate::Result<()> {
        let mut schema_builder = Schema::builder();
        schema_builder.add_text_field("name", TEXT | STORED);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema.clone());
        let name = schema.get_field("name").unwrap();

        {
            let mut index_writer = index.writer_for_tests()?;
            index_writer.add_document(doc!(name => "tantivy"));
            index_writer.add_document(doc!(name => "horse"));
            index_writer.add_document(doc!(name => "jockey"));
            index_writer.add_document(doc!(name => "cap"));
            // we should now have one segment with two docs
            index_writer.commit()?;
        }

        {
            let mut index_writer2 = index.writer(50_000_000)?;
            index_writer2.delete_term(Term::from_field_text(name, "horse"));
            index_writer2.delete_term(Term::from_field_text(name, "cap"));

            // ok, now we should have a deleted doc
            index_writer2.commit()?;
        }
        let searcher = index.reader()?.searcher();
        let docs: Vec<DocId> = searcher.segment_reader(0).doc_ids_alive().collect();
        assert_eq!(vec![0u32, 2u32], docs);
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use x11::xlib;
use super::super::libx;

use super::config::Config;
use super::{ Workspace, Workspaces };
use super::handler;

unsafe extern fn error_handler(display: *mut xlib::Display, event: *mut xlib::XErrorEvent) -> libc::c_int {
    // match event.error_code {
    //     xlib::BadAtom => {
    //         println!("bad atom");
    //     }
    //     _ => {}
    // }
    1
}

pub struct WindowManager {
    pub context: libx::Context,
    pub screen_num: libc::c_int,
    pub root:    xlib::Window,

    pub workspaces: Workspaces,
    config: Config
}

impl WindowManager {
    pub fn new() -> WindowManager {
	let context = libx::open_display(None);
        let context = match context {
            Some(p) => {
                p
            }
            None => {
                panic!("can't open display")
            }
        };

	let screen_num  = libx::default_screen(context);
	let root = libx::root_window(context, screen_num);
        println!("root window {}", root);
	let mut wm = WindowManager {
            context: context,
            screen_num: screen_num,
	    root: root,

            config: Config::load(),
            workspaces: Workspaces::new()
        };
        wm.workspaces.create('1', screen_num);
        wm.workspaces.get('1').unwrap().visible = true;
        wm.workspaces.switch_current('1', context);
        wm
    }

    pub fn clean(&mut self) {
        libx::close_display(self.context);
    }

    pub fn is_top_window(&self, window: xlib::Window) -> bool{
        let attrs = libx::get_window_attributes(self.context, window);
        let transientfor_hint = libx::get_transient_for_hint(self.context, window);
        attrs.override_redirect == 0 && transientfor_hint == 0
    }

    pub fn handle_create(&mut self, event: &xlib::XCreateWindowEvent) {
        if event.override_redirect != 0 {
            return;
        }

        let attrs = libx::get_window_attributes(self.context, event.window);

        // get window property
        let n = libx::get_text_property(self.context, event.window, xlib::XA_WM_NAME);
        match n {
            Some(s) => {debug!("create window {} for {}", event.window, s);}
            None => {}
        }

        // let atoms = libx::get_wm_protocols(self.context, event.window);
        // for a in atoms.iter() {
        //     println!("atom {}", a);
        //     let name = libx::get_atom_name(self.context, *a);
        //     match name {
        //         Some(n) => println!("name {}", n),
        //         None => println!("name {}", a),
        //     };
        // }
    }

    pub fn handle_destroy(&mut self, event: &xlib::XDestroyWindowEvent) {
        self.workspaces.remove_window(event.window, self.context);
    }

    pub fn handle_map_request(&mut self, event: &xlib::XMapRequestEvent) {
        libx::map_window(self.context, event.window);

        // add app top-level window to workspace
        let manage = self.is_top_window(event.window);

        if manage {
            debug!("top level window");
            self.workspaces.add_window(event.window, None, self.context);

            // change attributes before display
            let mask = 0x420010;
            let mask = xlib::EnterWindowMask | xlib::PropertyChangeMask;
            libx::select_input(self.context, event.window, mask);
        }
    }

    pub fn handle_client_message(&mut self, event: &xlib::XClientMessageEvent) {
        println!("message type {}", event.message_type);
        let s = libx::get_atom_name(self.context, event.message_type);
        match s {
            Some(v) => println!("{}", &v),
            None => {}
        }

        match event.format {
            8 => {
                for i in 0..20 {
                    println!("{}", event.data.get_byte(i));
                }
            }
            16 => {
                for i in 0..10 {
                    println!("{}", event.data.get_short(i))
                }
            }
            32 => {
                for i in 0..5 {
                    let a = event.data.get_long(i);
                    if a != 0{
                        let s = libx::get_atom_name(self.context, a as xlib::Atom);
                        match s {
                            Some(v) => println!("{}", v),
                            None => {}
                        }
                    }
                }
            }
            _ => {}
        }
    }

    pub fn handle_button_motion(&mut self, event: &xlib::XMotionEvent) {
        let (window, _) = libx::get_input_focus(self.context);
        if window != event.window {
            libx::set_input_focus(self.context, window);
        }
    }

    pub fn handle_key_release(&mut self, event: &xlib::XKeyEvent) {
        if event.state > 0 {
            let sym = libx::lookup_keysym(*event, 0);
            let b = handler::KeyBind {
                key: sym,
                mask: event.state,
            };
            debug!("key {} {}", event.state, sym);

            match self.config.bindsyms.get_mut(&b) {
                Some(handler) => {
                    handler.handle(&mut self.workspaces, self.context, self.screen_num);
                }
                None => {
                    println!("no bind");
                }
            }
        }
    }

    pub fn handle_property(&mut self, event: &xlib::XPropertyEvent) {
        let usertime = libx::get_atom(self.context, "_NET_WM_USER_TIME");
        match event.atom {
            usertime => {
                debug!("_NET_WM_USER_TIME");
                self.workspaces.set_focus(event.window, self.context);
            }
        }
    }

    pub fn handle_configure_request(&mut self, event: &xlib::XConfigureRequestEvent) {
        let mut change = xlib::XWindowChanges {
            x: event.x,
            y: event.y,
            width: event.width,
            height: event.height,
            border_width: event.border_width,
            sibling: event.above,
            stack_mode: event.detail
        };
        debug!("config x: {}, y: {}, width: {}, height: {}",
               change.x, change.y, change.width, change.height);
        libx::configure_window(self.context, event.window, event.value_mask as u32, change);
    }

    pub fn handle_focus_in(&mut self, event: &xlib::XFocusChangeEvent) {
        libx::set_input_focus(self.context, event.window);
        let (window, _) = libx::get_input_focus(self.context);
        println!("window {}", window);
      }

    pub fn handle_enter(&mut self, event: &xlib::XCrossingEvent){
        let (w, _) = libx::get_input_focus(self.context);
        println!("current focus {}", w);
        println!("focus {}", event.focus);
        if event.focus == 0 {
            libx::set_input_focus(self.context, event.window);
        }
    }

    pub fn handle(&mut self, e: xlib::XEvent) {
        let t = e.get_type();
        match t {
            xlib::CreateNotify => {
                let event: xlib::XCreateWindowEvent = From::from(e);
                debug!("create notify {}", event.window);
                self.handle_create(&event);
            }
            xlib::DestroyNotify => {
                let event: xlib::XDestroyWindowEvent = From::from(e);
                debug!("destroy notify {}", event.window);
                self.handle_destroy(&event);
            }
            xlib::MapNotify => {
                let event: xlib::XMapEvent = From::from(e);
                debug!("map notify {}", event.window);
            }
            xlib::UnmapNotify => {
                let event: xlib::XUnmapEvent = From::from(e);
                debug!("unmap notify {}", event.window);
            }
            xlib::MapRequest => {
                let event: xlib::XMapRequestEvent = From::from(e);
                debug!("map request {}", event.window);
                self.handle_map_request(&event);
            }
            xlib::ClientMessage => {
                debug!("client message");
                // let event = cast_event::<xlib::XClientMessageEvent>(&e);
                let event: xlib::XClientMessageEvent = From::from(e);
                self.handle_client_message(&event);
            }
            xlib::KeyRelease => {
                debug!("key release");
                let mut event: xlib::XKeyEvent = From::from(e);
                self.handle_key_release(&mut event);
            }
            xlib::MotionNotify => {
                let mut event: xlib::XMotionEvent = From::from(e);
                debug!("button motion {}", event.window);
                self.handle_button_motion(&event);
            }
            xlib::ButtonRelease => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button release {}", event.window);
                println!("{}", self.workspaces.get_focus(self.context));
            }
            xlib::ButtonPress => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button press {}", event.window);
            }
            xlib::ConfigureNotify => {
                debug!("configure notify");
            }
            xlib::ConfigureRequest =>{
                let mut event: xlib::XConfigureRequestEvent = From::from(e);
                debug!("configure request {}", event.window);
                self.handle_configure_request(&event);
            }
            xlib::FocusIn => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus in {}", event.window);
                self.handle_focus_in(&event);

            }
            xlib::FocusOut => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus out {}", event.window);
            }
            xlib::EnterNotify => {
                let mut event: xlib::XCrossingEvent = From::from(e);
                debug!("enter window {}", event.window);
                self.handle_enter(&event);
            }
            xlib::PropertyNotify => {
                let mut event: xlib::XPropertyEvent = From::from(e);
                debug!("property notify {}", event.window);
                self.handle_property(&event);
            }
            _ => {
                debug!("unhandled event {}", t);
            }
        }
    }
    pub fn run(&mut self) {
        loop {
            //handle events here
            let mut e = libx::next_event(self.context);
            self.handle(e);
        }
    }

    pub fn init(&mut self) {
        let mask = 0x1A0034;
        let mask = xlib::SubstructureRedirectMask | xlib::SubstructureNotifyMask;

        unsafe{
            // xlib::XSetErrorHandler(Some(error_handler));
        }
        let left_ptr: u32 = 68;
        libx::define_cursor(self.context, self.root, left_ptr);

        libx::ungrab_button(self.context, 0, 0x8000, self.root);
        libx::select_input(self.context, self.root,
                           mask);

        for bind in self.config.bindsyms.keys() {
            let code = libx::keysym_to_keycode(self.context, bind.key);
            libx::grab_key(self.context, code, bind.mask, self.root);
        }
        // let anymodifier = 1 << 15;
        // libx::grab_button(self.context, 0, anymodifier, self.root);
        libx::sync(self.context, 0);
    }
}
<commit_msg>use Window<commit_after>extern crate libc;

use x11::xlib;
use super::super::libx;

use super::config::Config;
use super::Window;
use super::{ Workspace, Workspaces };
use super::handler;

unsafe extern fn error_handler(display: *mut xlib::Display, event: *mut xlib::XErrorEvent) -> libc::c_int {
    // match event.error_code {
    //     xlib::BadAtom => {
    //         println!("bad atom");
    //     }
    //     _ => {}
    // }
    1
}

pub struct WindowManager {
    pub context: libx::Context,
    pub screen_num: libc::c_int,
    pub root:    xlib::Window,

    pub workspaces: Workspaces,
    config: Config
}

impl WindowManager {
    pub fn new() -> WindowManager {
	let context = libx::open_display(None);
        let context = match context {
            Some(p) => {
                p
            }
            None => {
                panic!("can't open display")
            }
        };

	let screen_num  = libx::default_screen(context);
	let root = libx::root_window(context, screen_num);
        println!("root window {}", root);
	let mut wm = WindowManager {
            context: context,
            screen_num: screen_num,
	    root: root,

            config: Config::load(),
            workspaces: Workspaces::new()
        };
        wm.workspaces.create('1', screen_num);
        wm.workspaces.get('1').unwrap().visible = true;
        wm.workspaces.switch_current('1', context);
        wm
    }

    pub fn clean(&mut self) {
        libx::close_display(self.context);
    }

    pub fn is_top_window(&self, window: xlib::Window) -> bool{
        let attrs = libx::get_window_attributes(self.context, window);
        let transientfor_hint = libx::get_transient_for_hint(self.context, window);
        attrs.override_redirect == 0 && transientfor_hint == 0
    }

    pub fn handle_create(&mut self, event: &xlib::XCreateWindowEvent) {
        if event.override_redirect != 0 {
            return;
        }

        let attrs = libx::get_window_attributes(self.context, event.window);

        // get window property
        let n = libx::get_text_property(self.context, event.window, xlib::XA_WM_NAME);
        match n {
            Some(s) => {debug!("create window {} for {}", event.window, s);}
            None => {}
        }

        // let atoms = libx::get_wm_protocols(self.context, event.window);
        // for a in atoms.iter() {
        //     println!("atom {}", a);
        //     let name = libx::get_atom_name(self.context, *a);
        //     match name {
        //         Some(n) => println!("name {}", n),
        //         None => println!("name {}", a),
        //     };
        // }
    }

    pub fn handle_destroy(&mut self, event: &xlib::XDestroyWindowEvent) {
        let window = Window::new(self.context, event.window);
        self.workspaces.remove_window(window, self.context);
    }

    pub fn handle_map_request(&mut self, event: &xlib::XMapRequestEvent) {
        let window = Window::new(self.context, event.window);
        window.map();

        // add app top-level window to workspace
        let manage = self.is_top_window(event.window);

        if manage {
            debug!("top level window");
            let window = Window::new(self.context, event.window);
            self.workspaces.add_window(window, None, self.context);

            // change attributes before display
            let mask = 0x420010;
            let mask = xlib::EnterWindowMask | xlib::PropertyChangeMask;
            libx::select_input(self.context, event.window, mask);
        }
    }

    pub fn handle_client_message(&mut self, event: &xlib::XClientMessageEvent) {
        println!("message type {}", event.message_type);
        let s = libx::get_atom_name(self.context, event.message_type);
        match s {
            Some(v) => println!("{}", &v),
            None => {}
        }

        match event.format {
            8 => {
                for i in 0..20 {
                    println!("{}", event.data.get_byte(i));
                }
            }
            16 => {
                for i in 0..10 {
                    println!("{}", event.data.get_short(i))
                }
            }
            32 => {
                for i in 0..5 {
                    let a = event.data.get_long(i);
                    if a != 0{
                        let s = libx::get_atom_name(self.context, a as xlib::Atom);
                        match s {
                            Some(v) => println!("{}", v),
                            None => {}
                        }
                    }
                }
            }
            _ => {}
        }
    }

    pub fn handle_button_motion(&mut self, event: &xlib::XMotionEvent) {
        let (window, _) = libx::get_input_focus(self.context);
        if window != event.window {
            libx::set_input_focus(self.context, window);
        }
    }

    pub fn handle_key_release(&mut self, event: &xlib::XKeyEvent) {
        if event.state > 0 {
            let sym = libx::lookup_keysym(*event, 0);
            let b = handler::KeyBind {
                key: sym,
                mask: event.state,
            };
            debug!("key {} {}", event.state, sym);

            match self.config.bindsyms.get_mut(&b) {
                Some(handler) => {
                    handler.handle(&mut self.workspaces, self.context, self.screen_num);
                }
                None => {
                    println!("no bind");
                }
            }
        }
    }

    pub fn handle_property(&mut self, event: &xlib::XPropertyEvent) {
        let usertime = libx::get_atom(self.context, "_NET_WM_USER_TIME");
        match event.atom {
            usertime => {
                debug!("_NET_WM_USER_TIME");
                let window = Window::new(self.context, event.window);
                self.workspaces.set_focus(window, self.context);
            }
        }
    }

    pub fn handle_configure_request(&mut self, event: &xlib::XConfigureRequestEvent) {
        let mut change = xlib::XWindowChanges {
            x: event.x,
            y: event.y,
            width: event.width,
            height: event.height,
            border_width: event.border_width,
            sibling: event.above,
            stack_mode: event.detail
        };
        debug!("config x: {}, y: {}, width: {}, height: {}",
               change.x, change.y, change.width, change.height);
        libx::configure_window(self.context, event.window, event.value_mask as u32, change);
    }

    pub fn handle_focus_in(&mut self, event: &xlib::XFocusChangeEvent) {
        libx::set_input_focus(self.context, event.window);
        let (window, _) = libx::get_input_focus(self.context);
        println!("window {}", window);
      }

    pub fn handle_enter(&mut self, event: &xlib::XCrossingEvent){
        let (w, _) = libx::get_input_focus(self.context);
        println!("current focus {}", w);
        println!("focus {}", event.focus);
        if event.focus == 0 {
            libx::set_input_focus(self.context, event.window);
        }
    }

    pub fn handle(&mut self, e: xlib::XEvent) {
        let t = e.get_type();
        match t {
            xlib::CreateNotify => {
                let event: xlib::XCreateWindowEvent = From::from(e);
                debug!("create notify {}", event.window);
                self.handle_create(&event);
            }
            xlib::DestroyNotify => {
                let event: xlib::XDestroyWindowEvent = From::from(e);
                debug!("destroy notify {}", event.window);
                self.handle_destroy(&event);
            }
            xlib::MapNotify => {
                let event: xlib::XMapEvent = From::from(e);
                debug!("map notify {}", event.window);
            }
            xlib::UnmapNotify => {
                let event: xlib::XUnmapEvent = From::from(e);
                debug!("unmap notify {}", event.window);
            }
            xlib::MapRequest => {
                let event: xlib::XMapRequestEvent = From::from(e);
                debug!("map request {}", event.window);
                self.handle_map_request(&event);
            }
            xlib::ClientMessage => {
                debug!("client message");
                // let event = cast_event::<xlib::XClientMessageEvent>(&e);
                let event: xlib::XClientMessageEvent = From::from(e);
                self.handle_client_message(&event);
            }
            xlib::KeyRelease => {
                debug!("key release");
                let mut event: xlib::XKeyEvent = From::from(e);
                self.handle_key_release(&mut event);
            }
            xlib::MotionNotify => {
                let mut event: xlib::XMotionEvent = From::from(e);
                debug!("button motion {}", event.window);
                self.handle_button_motion(&event);
            }
            xlib::ButtonRelease => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button release {}", event.window);
                println!("{}", self.workspaces.get_focus(self.context).id);
            }
            xlib::ButtonPress => {
                let mut event: xlib::XButtonEvent = From::from(e);
                debug!("button press {}", event.window);
            }
            xlib::ConfigureNotify => {
                debug!("configure notify");
            }
            xlib::ConfigureRequest =>{
                let mut event: xlib::XConfigureRequestEvent = From::from(e);
                debug!("configure request {}", event.window);
                self.handle_configure_request(&event);
            }
            xlib::FocusIn => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus in {}", event.window);
                self.handle_focus_in(&event);

            }
            xlib::FocusOut => {
                let mut event: xlib::XFocusChangeEvent = From::from(e);
                debug!("focus out {}", event.window);
            }
            xlib::EnterNotify => {
                let mut event: xlib::XCrossingEvent = From::from(e);
                debug!("enter window {}", event.window);
                self.handle_enter(&event);
            }
            xlib::PropertyNotify => {
                let mut event: xlib::XPropertyEvent = From::from(e);
                debug!("property notify {}", event.window);
                self.handle_property(&event);
            }
            _ => {
                debug!("unhandled event {}", t);
            }
        }
    }
    pub fn run(&mut self) {
        loop {
            //handle events here
            let mut e = libx::next_event(self.context);
            self.handle(e);
        }
    }

    pub fn init(&mut self) {
        let mask = 0x1A0034;
        let mask = xlib::SubstructureRedirectMask | xlib::SubstructureNotifyMask;

        unsafe{
            // xlib::XSetErrorHandler(Some(error_handler));
        }
        let left_ptr: u32 = 68;
        libx::define_cursor(self.context, self.root, left_ptr);

        libx::ungrab_button(self.context, 0, 0x8000, self.root);
        libx::select_input(self.context, self.root,
                           mask);

        for bind in self.config.bindsyms.keys() {
            let code = libx::keysym_to_keycode(self.context, bind.key);
            libx::grab_key(self.context, code, bind.mask, self.root);
        }
        // let anymodifier = 1 << 15;
        // libx::grab_button(self.context, 0, anymodifier, self.root);
        libx::sync(self.context, 0);
    }
}
<|endoftext|>


<commit_before>//! [Scott numerals](http://lucacardelli.name/Papers/Notes/scott2.pdf)

use data::boolean::{tru, fls};
use term::{Term, abs, app};
use term::Term::*;

/// Produces a Scott-encoded number zero.
///
/// ZERO := λxy.x = λ λ 2
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::zero;
/// use lambda_calculus::*;
///
/// assert_eq!(zero(), 0.into_scott());
/// ```
pub fn zero() -> Term { abs!(2, Var(2)) }

/// Applied to a Scott-encoded number it produces a lambda-encoded boolean, indicating whether its
/// argument is equal to zero.
///
/// IS_ZERO := λn.n TRUE (λx.FALSE) =  λ 1 TRUE (λ FALSE)
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::is_zero;
/// use lambda_calculus::data::boolean::{tru, fls};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(is_zero(), 0.into_scott()), NOR, 0), tru());
/// assert_eq!(beta(app(is_zero(), 1.into_scott()), NOR, 0), fls());
/// ```
pub fn is_zero() -> Term {
    abs(app!(Var(1), tru(), abs(fls())))
}

/// Produces a Scott-encoded number one.
///
/// ONE := λab.b ZERO = λ λ 1 ZERO
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::one;
/// use lambda_calculus::*;
///
/// assert_eq!(one(), 1.into_scott());
/// ```
pub fn one() -> Term { abs!(2, app(Var(1), abs!(2, Var(2)))) }

/// Applied to a Scott-encoded number it produces its successor.
///
/// SUCC := λnxy.y n = λ λ λ 1 3
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::succ;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(succ(), 0.into_scott()), NOR, 0), 1.into_scott());
/// assert_eq!(beta(app(succ(), 1.into_scott()), NOR, 0), 2.into_scott());
/// ```
pub fn succ() -> Term {
    abs!(3, app(Var(1), Var(3)))
}

/// Applied to a Scott-encoded number it produces its predecessor.
///
/// PRED := λn.n ZERO (λx.x) = λ 1 ZERO (λ 1)
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::pred;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(pred(), 1.into_scott()), NOR, 0), 0.into_scott());
/// assert_eq!(beta(app(pred(), 3.into_scott()), NOR, 0), 2.into_scott());
/// ```
pub fn pred() -> Term {
    abs(app!(Var(1), zero(), abs(Var(1))))
}
<commit_msg>add church_to_scott function<commit_after>//! [Scott numerals](http://lucacardelli.name/Papers/Notes/scott2.pdf)

use data::boolean::{tru, fls};
use term::{Term, abs, app};
use term::Term::*;

/// Produces a Scott-encoded number zero.
///
/// ZERO := λxy.x = λ λ 2
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::zero;
/// use lambda_calculus::*;
///
/// assert_eq!(zero(), 0.into_scott());
/// ```
pub fn zero() -> Term { abs!(2, Var(2)) }

/// Applied to a Scott-encoded number it produces a lambda-encoded boolean, indicating whether its
/// argument is equal to zero.
///
/// IS_ZERO := λn.n TRUE (λx.FALSE) =  λ 1 TRUE (λ FALSE)
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::is_zero;
/// use lambda_calculus::data::boolean::{tru, fls};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(is_zero(), 0.into_scott()), NOR, 0), tru());
/// assert_eq!(beta(app(is_zero(), 1.into_scott()), NOR, 0), fls());
/// ```
pub fn is_zero() -> Term {
    abs(app!(Var(1), tru(), abs(fls())))
}

/// Produces a Scott-encoded number one.
///
/// ONE := λab.b ZERO = λ λ 1 ZERO
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::one;
/// use lambda_calculus::*;
///
/// assert_eq!(one(), 1.into_scott());
/// ```
pub fn one() -> Term { abs!(2, app(Var(1), abs!(2, Var(2)))) }

/// Applied to a Scott-encoded number it produces its successor.
///
/// SUCC := λnxy.y n = λ λ λ 1 3
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::succ;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(succ(), 0.into_scott()), NOR, 0), 1.into_scott());
/// assert_eq!(beta(app(succ(), 1.into_scott()), NOR, 0), 2.into_scott());
/// ```
pub fn succ() -> Term {
    abs!(3, app(Var(1), Var(3)))
}

/// Applied to a Scott-encoded number it produces its predecessor.
///
/// PRED := λn.n ZERO (λx.x) = λ 1 ZERO (λ 1)
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::pred;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(pred(), 1.into_scott()), NOR, 0), 0.into_scott());
/// assert_eq!(beta(app(pred(), 3.into_scott()), NOR, 0), 2.into_scott());
/// ```
pub fn pred() -> Term {
    abs(app!(Var(1), zero(), abs(Var(1))))
}

/// Applied to a Church-encoded number it produces the equivalent Scott-encoded number.
///
/// CHURCH_TO_SCOTT := λn.n SUCC ZERO = λ 1 SUCC ZERO
///
/// # Example
/// ```
/// use lambda_calculus::data::numerals::scott::church_to_scott;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(church_to_scott(), 0.into_church()), NOR, 0), 0.into_scott());
/// assert_eq!(beta(app(church_to_scott(), 1.into_church()), NOR, 0), 1.into_scott());
/// assert_eq!(beta(app(church_to_scott(), 2.into_church()), NOR, 0), 2.into_scott());
/// ```
pub fn church_to_scott() -> Term {
    abs(app!(Var(1), succ(), zero()))
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

#[derive(Debug, Clone, Copy)]
enum Direction {
  Left,
  Right,
  Up,
  Down
}

type Wire = Vec<(Direction, usize)>;
type Grid = HashMap<(i32, i32), HashMap<usize, usize>>;

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("03.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn norm((x, y): (i32, i32)) -> i32 {
  x.abs() + y.abs()
}

fn parse_wires(input: &str) -> Vec<Wire> {
  input.lines()
  .map(|line| {
    line.split(',')
    .filter_map(|token| {
      let direction = token.chars().nth(0);
      let steps = &token[1..];

      steps.parse::<usize>().ok()
      .and_then(|steps| {
        match direction {
          Some('L') => Some(Direction::Left),
          Some('R') => Some(Direction::Right),
          Some('U') => Some(Direction::Up),
          Some('D') => Some(Direction::Down),
          _ => None
        }
        .map(|direction| (direction, steps))
      })
    })
    .collect::<Vec<_>>()
  })
  .collect::<Vec<_>>()
}

fn trace_wire(grid: &mut Grid, id: usize, wire: &Wire) {
  let mut position = (0, 0);
  let mut timestamp = 0;

  for &(direction, steps) in wire.iter() {
    let move_vector = match direction {
      Direction::Left => (-1, 0),
      Direction::Right => (1, 0),
      Direction::Up => (0, 1),
      Direction::Down => (0, -1)
    };

    for _ in 0..steps {
      position = (position.0 + move_vector.0, position.1 + move_vector.1);
      timestamp += 1;

      if !grid.contains_key(&position) {
        grid.insert(position, HashMap::new());
      }

      let ids = grid.get_mut(&position).unwrap();

      if !ids.contains_key(&id) {
        ids.insert(id, timestamp);
      }
    }
  }
}

fn iter_collisions<'a>(grid: &'a Grid) -> impl Iterator<Item = (i32, i32)> + 'a {
  grid.iter()
  .filter(|(_, ids)| ids.len() > 1)
  .map(|(&pos, _)| pos)
}

fn iter_collision_times<'a>(grid: &'a Grid) -> impl Iterator<Item = usize> + 'a {
  iter_collisions(grid)
  .map(move |pos| {
    grid.get(&pos)
    .unwrap()
    .values()
    .sum()
  })
}

fn main() {
  let input = get_input().unwrap();
  let wires = parse_wires(&input);
  let mut grid = Grid::new();

  for (i, wire) in wires.iter().enumerate() {
    trace_wire(&mut grid, i, wire);
  }

  iter_collisions(&grid)
  .map(|pos| norm(pos))
  .min()
  .map(|min_collision_norm| {
    println!("Part 1: {}", min_collision_norm);
  });

  iter_collision_times(&grid)
  .min()
  .map(|min_collision_time| {
    println!("Part 2: {}", min_collision_time);
  });
}
<commit_msg>Simplify code<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

#[derive(Debug, Clone, Copy)]
enum Direction {
  Left,
  Right,
  Up,
  Down
}

type Wire = Vec<(Direction, usize)>;
type Grid = HashMap<(i32, i32), HashMap<usize, usize>>;

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("03.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn norm((x, y): (i32, i32)) -> i32 {
  x.abs() + y.abs()
}

fn parse_wires(input: &str) -> Vec<Wire> {
  input.lines()
  .map(|line| {
    line.split(',')
    .filter_map(|token| {
      if token.len() < 2 {
        return None;
      }

      let steps = token.get(1..).and_then(|steps| steps.parse::<usize>().ok());
      let direction = match token.chars().nth(0) {
        Some('L') => Some(Direction::Left),
        Some('R') => Some(Direction::Right),
        Some('U') => Some(Direction::Up),
        Some('D') => Some(Direction::Down),
        _ => None
      };

      match (direction, steps) {
        (Some(direction), Some(steps)) => Some((direction, steps)),
        _ => None
      }
    })
    .collect::<Vec<_>>()
  })
  .collect::<Vec<_>>()
}

fn trace_wire(grid: &mut Grid, id: usize, wire: &Wire) {
  let mut position = (0, 0);
  let mut timestamp = 0;

  for &(direction, steps) in wire.iter() {
    let move_vector = match direction {
      Direction::Left => (-1, 0),
      Direction::Right => (1, 0),
      Direction::Up => (0, 1),
      Direction::Down => (0, -1)
    };

    for _ in 0..steps {
      position = (position.0 + move_vector.0, position.1 + move_vector.1);
      timestamp += 1;

      if !grid.contains_key(&position) {
        grid.insert(position, HashMap::new());
      }

      let ids = grid.get_mut(&position).unwrap();

      if !ids.contains_key(&id) {
        ids.insert(id, timestamp);
      }
    }
  }
}

fn iter_collisions<'a>(grid: &'a Grid) -> impl Iterator<Item = (i32, i32)> + 'a {
  grid.iter()
  .filter(|(_, ids)| ids.len() > 1)
  .map(|(&pos, _)| pos)
}

fn iter_collision_times<'a>(grid: &'a Grid) -> impl Iterator<Item = usize> + 'a {
  iter_collisions(grid)
  .map(move |pos| {
    grid.get(&pos)
    .unwrap()
    .values()
    .sum()
  })
}

fn main() {
  let input = get_input().unwrap();
  let wires = parse_wires(&input);
  let mut grid = Grid::new();

  for (i, wire) in wires.iter().enumerate() {
    trace_wire(&mut grid, i, wire);
  }

  iter_collisions(&grid)
  .map(|pos| norm(pos))
  .min()
  .map(|min_collision_norm| {
    println!("Part 1: {}", min_collision_norm);
  });

  iter_collision_times(&grid)
  .min()
  .map(|min_collision_time| {
    println!("Part 2: {}", min_collision_time);
  });
}
<|endoftext|>


<commit_before>use common::*;
use std::fs::File;
use std::io::Read;
use super::{NetbricksConfiguration, PortConfiguration};
use toml::*;

/// Default configuration values
pub const DEFAULT_POOL_SIZE: u32 = 2048 - 1;
pub const DEFAULT_CACHE_SIZE: u32 = 32;
pub const DEFAULT_SECONDARY: bool = false;
pub const DEFAULT_PRIMARY_CORE: i32 = 0;
pub const DEFAULT_NAME: &'static str = "zcsi";
pub const NUM_RXD: i32 = 128;
pub const NUM_TXD: i32 = 128;

/// Read a TOML stub and figure out the port.
fn read_port(value: &Value) -> Result<PortConfiguration> {
    if let Value::Table(ref port_def) = *value {
        let name = match port_def.get("name") {
            Some(&Value::String(ref name)) => name.clone(),
            _ => return Err(ErrorKind::ConfigurationError(String::from("Could not parse name for port")).into()),
        };

        let rxd = match port_def.get("rxd") {
            Some(&Value::Integer(rxd)) => rxd as i32,
            None => NUM_RXD,
            v => {
                return Err(ErrorKind::ConfigurationError(format!("Could not parse number of rx descriptors {:?}", v))
                    .into())
            }
        };

        let txd = match port_def.get("txd") {
            Some(&Value::Integer(txd)) => txd as i32,
            None => NUM_TXD,
            v => {
                return Err(ErrorKind::ConfigurationError(format!("Could not parse number of tx descriptors {:?}", v))
                    .into())
            }
        };

        let loopback = match port_def.get("loopback") {
            Some(&Value::Boolean(l)) => l,
            None => false,
            v => return Err(ErrorKind::ConfigurationError(format!("Could not parse loopback spec {:?}", v)).into()),
        };

        let tso = match port_def.get("tso") {
            Some(&Value::Boolean(l)) => l,
            None => false,
            v => return Err(ErrorKind::ConfigurationError(format!("Could not parse tso spec {:?}", v)).into()),
        };

        let csum = match port_def.get("checksum") {
            Some(&Value::Boolean(l)) => l,
            None => false,
            v => return Err(ErrorKind::ConfigurationError(format!("Could not parse csum spec {:?}", v)).into()),
        };

        let symmetric_queue = port_def.contains_key("cores");
        if symmetric_queue && (port_def.contains_key("rx_cores") || port_def.contains_key("tx_cores")) {
            println!("cores specified along with rx_cores and/or tx_cores for port {}",
                     name);
            return Err(ErrorKind::ConfigurationError(format!("cores specified along with rx_cores and/or tx_cores \
                                                              for port {}",
                                                             name))
                .into());
        }

        fn read_queue(queue: &Value) -> Result<Vec<i32>> {
            match *queue {
                Value::Array(ref queues) => {
                    let mut qs = Vec::with_capacity(queues.len());
                    for q in queues {
                        if let Value::Integer(core) = *q {
                            qs.push(core as i32)
                        } else {
                            return Err(ErrorKind::ConfigurationError(format!("Could not parse queue spec {:?}", q))
                                .into());
                        };
                    }
                    Ok(qs)
                }
                Value::Integer(core) => Ok(vec![core as i32]),
                _ => Ok(vec![]),
            }
        }

        let rx_queues = if symmetric_queue {
            try!(read_queue(port_def.get("cores").unwrap()))
        } else {
            match port_def.get("rx_cores") {
                Some(v) => try!(read_queue(v)),
                None => Vec::with_capacity(0),
            }
        };

        let tx_queues = if symmetric_queue {
            rx_queues.clone()
        } else {
            match port_def.get("tx_cores") {
                Some(v) => try!(read_queue(v)),
                None => Vec::with_capacity(0),
            }
        };

        Ok(PortConfiguration {
            name: name,
            rx_queues: rx_queues,
            tx_queues: tx_queues,
            rxd: rxd,
            txd: txd,
            loopback: loopback,
            csum: csum,
            tso: tso,
        })
    } else {
        Err(ErrorKind::ConfigurationError(String::from("Could not understand port spec")).into())
    }
}

/// Read a TOML string and create a `NetbricksConfiguration` structure.
/// `configuration` is a TOML formatted string.
/// `filename` is used for error reporting purposes, and is otherwise meaningless.
pub fn read_configuration_from_str(configuration: &str, filename: &str) -> Result<NetbricksConfiguration> {
    // Parse string for TOML file.
    let mut parser = Parser::new(configuration);
    let toml = match parser.parse() {
        Some(toml) => toml,
        None => {
            for err in &parser.errors {
                // FIXME: Change to logging
                let (loline, locol) = parser.to_linecol(err.lo);
                let (hiline, hicol) = parser.to_linecol(err.hi);
                println!("Parse error error: {} file {} location {}:{} -- {}:{}",
                         err.desc,
                         filename,
                         loline,
                         locol,
                         hicol,
                         hiline);
            }
            return Err(ErrorKind::ConfigurationError(format!("Experienced {} parse errors in spec.",
                                                             parser.errors.len()))
                .into());
        }
    };

    // Get name from configuration
    let name = match toml.get("name") {
        Some(&Value::String(ref name)) => name.clone(),
        None => String::from(DEFAULT_NAME),
        _ => {
            println!("Could not parse name");
            return Err(ErrorKind::ConfigurationError(String::from("Could not parse name")).into());
        }
    };

    // Get primary core from configuration.
    let master_lcore = match toml.get("master_core") {
        Some(&Value::Integer(core)) => core as i32,
        Some(&Value::String(ref core)) => {
            match core.parse() {
                Ok(c) => c,
                _ => return Err(ErrorKind::ConfigurationError(format!("Could not parse {} as core", core)).into()),
            }
        }
        None => DEFAULT_PRIMARY_CORE,
        v => {
            println!("Could not parse core");
            return Err(ErrorKind::ConfigurationError(format!("Could not parse {:?} as core", v)).into());
        }
    };

    // Parse mempool size
    let pool_size = match toml.get("pool_size") {
        Some(&Value::Integer(pool)) => pool as u32,
        None => DEFAULT_POOL_SIZE,
        _ => {
            println!("Could parse pool size");
            return Err(ErrorKind::ConfigurationError(String::from("Could not parse pool size")).into());
        }
    };

    // Get cache size
    let cache_size = match toml.get("cache_size") {
        Some(&Value::Integer(cache)) => cache as u32,
        None => DEFAULT_CACHE_SIZE,
        _ => {
            println!("Could parse cache size");
            return Err(ErrorKind::ConfigurationError(String::from("Could not parse cache size")).into());
        }
    };

    // Is process a secondary process
    let secondary = match toml.get("secondary") {
        Some(&Value::Boolean(secondary)) => secondary,
        None => DEFAULT_SECONDARY,
        _ => {
            println!("Could not parse whether this is a secondary process");
            return Err(ErrorKind::ConfigurationError(String::from("Could not parse secondary processor spec")).into());
        }
    };

    // Secondary ports to instantiate.
    let cores = match toml.get("cores") {
        Some(&Value::Array(ref c)) => {
            let mut cores = Vec::with_capacity(c.len());
            for core in c {
                if let Value::Integer(core) = *core {
                    cores.push(core as i32)
                } else {
                    return Err(ErrorKind::ConfigurationError(format!("Could not parse core spec {}", core)).into());
                }
            }
            cores
        }
        None => Vec::with_capacity(0),
        _ => {
            println!("Cores is not an array");
            return Err(ErrorKind::ConfigurationError(String::from("Cores is not an array")).into());
        }
    };

    let strict = match toml.get("strict") {
        Some(&Value::Boolean(l)) => l,
        None => false,
        v => {
            return Err(ErrorKind::ConfigurationError(format!("Could not parse strict spec (should be boolean) {:?}",
                                                             v))
                .into())
        }
    };

    let ports = match toml.get("ports") {
        Some(&Value::Array(ref ports)) => {
            let mut pouts = Vec::with_capacity(ports.len());
            for port in ports {
                let p = try!(read_port(port));
                pouts.push(p);
                // match read_port(port) {
            }
            pouts
        }
        None => Vec::with_capacity(0),
        _ => {
            println!("Ports is not an array");
            return Err(ErrorKind::ConfigurationError(String::from("Ports is not an array")).into());
        }
    };

    Ok(NetbricksConfiguration {
        name: name,
        primary_core: master_lcore,
        cores: cores,
        strict: strict,
        secondary: secondary,
        pool_size: pool_size,
        cache_size: cache_size,
        ports: ports,
    })
}

/// Read a configuration file and create a `NetbricksConfiguration` structure.
/// `filename` should be TOML formatted file.
pub fn read_configuration(filename: &str) -> Result<NetbricksConfiguration> {
    let mut toml_str = String::new();
    let _ = try!{File::open(filename).and_then(|mut f| f.read_to_string(&mut toml_str))
        .chain_err(|| ErrorKind::ConfigurationError(String::from("Could not read file")))};
    read_configuration_from_str(&toml_str[..], filename)
}
<commit_msg>Update config_reader to new TOML (#44)<commit_after>use common::*;
use std::fs::File;
use std::io::Read;
use super::{NetbricksConfiguration, PortConfiguration};
use toml::{self, Value};

/// Default configuration values
pub const DEFAULT_POOL_SIZE: u32 = 2048 - 1;
pub const DEFAULT_CACHE_SIZE: u32 = 32;
pub const DEFAULT_SECONDARY: bool = false;
pub const DEFAULT_PRIMARY_CORE: i32 = 0;
pub const DEFAULT_NAME: &'static str = "zcsi";
pub const NUM_RXD: i32 = 128;
pub const NUM_TXD: i32 = 128;

/// Read a TOML stub and figure out the port.
fn read_port(value: &Value) -> Result<PortConfiguration> {
    if let Value::Table(ref port_def) = *value {
        let name = match port_def.get("name") {
            Some(&Value::String(ref name)) => name.clone(),
            _ => return Err(ErrorKind::ConfigurationError(String::from("Could not parse name for port")).into()),
        };

        let rxd = match port_def.get("rxd") {
            Some(&Value::Integer(rxd)) => rxd as i32,
            None => NUM_RXD,
            v => {
                return Err(ErrorKind::ConfigurationError(format!("Could not parse number of rx descriptors {:?}", v))
                    .into())
            }
        };

        let txd = match port_def.get("txd") {
            Some(&Value::Integer(txd)) => txd as i32,
            None => NUM_TXD,
            v => {
                return Err(ErrorKind::ConfigurationError(format!("Could not parse number of tx descriptors {:?}", v))
                    .into())
            }
        };

        let loopback = match port_def.get("loopback") {
            Some(&Value::Boolean(l)) => l,
            None => false,
            v => return Err(ErrorKind::ConfigurationError(format!("Could not parse loopback spec {:?}", v)).into()),
        };

        let tso = match port_def.get("tso") {
            Some(&Value::Boolean(l)) => l,
            None => false,
            v => return Err(ErrorKind::ConfigurationError(format!("Could not parse tso spec {:?}", v)).into()),
        };

        let csum = match port_def.get("checksum") {
            Some(&Value::Boolean(l)) => l,
            None => false,
            v => return Err(ErrorKind::ConfigurationError(format!("Could not parse csum spec {:?}", v)).into()),
        };

        let symmetric_queue = port_def.contains_key("cores");
        if symmetric_queue && (port_def.contains_key("rx_cores") || port_def.contains_key("tx_cores")) {
            println!("cores specified along with rx_cores and/or tx_cores for port {}",
                     name);
            return Err(ErrorKind::ConfigurationError(format!("cores specified along with rx_cores and/or tx_cores \
                                                              for port {}",
                                                             name))
                .into());
        }

        fn read_queue(queue: &Value) -> Result<Vec<i32>> {
            match *queue {
                Value::Array(ref queues) => {
                    let mut qs = Vec::with_capacity(queues.len());
                    for q in queues {
                        if let Value::Integer(core) = *q {
                            qs.push(core as i32)
                        } else {
                            return Err(ErrorKind::ConfigurationError(format!("Could not parse queue spec {:?}", q))
                                .into());
                        };
                    }
                    Ok(qs)
                }
                Value::Integer(core) => Ok(vec![core as i32]),
                _ => Ok(vec![]),
            }
        }

        let rx_queues = if symmetric_queue {
            try!(read_queue(port_def.get("cores").unwrap()))
        } else {
            match port_def.get("rx_cores") {
                Some(v) => try!(read_queue(v)),
                None => Vec::with_capacity(0),
            }
        };

        let tx_queues = if symmetric_queue {
            rx_queues.clone()
        } else {
            match port_def.get("tx_cores") {
                Some(v) => try!(read_queue(v)),
                None => Vec::with_capacity(0),
            }
        };

        Ok(PortConfiguration {
            name: name,
            rx_queues: rx_queues,
            tx_queues: tx_queues,
            rxd: rxd,
            txd: txd,
            loopback: loopback,
            csum: csum,
            tso: tso,
        })
    } else {
        Err(ErrorKind::ConfigurationError(String::from("Could not understand port spec")).into())
    }
}

/// Read a TOML string and create a `NetbricksConfiguration` structure.
/// `configuration` is a TOML formatted string.
/// `filename` is used for error reporting purposes, and is otherwise meaningless.
pub fn read_configuration_from_str(configuration: &str, filename: &str) -> Result<NetbricksConfiguration> {
    // Parse string for TOML file.
    let toml = match toml::de::from_str::<Value>(configuration) {
        Ok(toml) => toml,
        Err(error) => {
            println!("Parse error: {} in file: {}", error, filename);
            return Err(ErrorKind::ConfigurationError(format!("Experienced {} parse errors in spec.", error)).into());
        }
    };

    // Get name from configuration
    let name = match toml.get("name") {
        Some(&Value::String(ref name)) => name.clone(),
        None => String::from(DEFAULT_NAME),
        _ => {
            println!("Could not parse name");
            return Err(ErrorKind::ConfigurationError(String::from("Could not parse name")).into());
        }
    };

    // Get primary core from configuration.
    let master_lcore = match toml.get("master_core") {
        Some(&Value::Integer(core)) => core as i32,
        Some(&Value::String(ref core)) => {
            match core.parse() {
                Ok(c) => c,
                _ => return Err(ErrorKind::ConfigurationError(format!("Could not parse {} as core", core)).into()),
            }
        }
        None => DEFAULT_PRIMARY_CORE,
        v => {
            println!("Could not parse core");
            return Err(ErrorKind::ConfigurationError(format!("Could not parse {:?} as core", v)).into());
        }
    };

    // Parse mempool size
    let pool_size = match toml.get("pool_size") {
        Some(&Value::Integer(pool)) => pool as u32,
        None => DEFAULT_POOL_SIZE,
        _ => {
            println!("Could parse pool size");
            return Err(ErrorKind::ConfigurationError(String::from("Could not parse pool size")).into());
        }
    };

    // Get cache size
    let cache_size = match toml.get("cache_size") {
        Some(&Value::Integer(cache)) => cache as u32,
        None => DEFAULT_CACHE_SIZE,
        _ => {
            println!("Could parse cache size");
            return Err(ErrorKind::ConfigurationError(String::from("Could not parse cache size")).into());
        }
    };

    // Is process a secondary process
    let secondary = match toml.get("secondary") {
        Some(&Value::Boolean(secondary)) => secondary,
        None => DEFAULT_SECONDARY,
        _ => {
            println!("Could not parse whether this is a secondary process");
            return Err(ErrorKind::ConfigurationError(String::from("Could not parse secondary processor spec")).into());
        }
    };

    // Secondary ports to instantiate.
    let cores = match toml.get("cores") {
        Some(&Value::Array(ref c)) => {
            let mut cores = Vec::with_capacity(c.len());
            for core in c {
                if let Value::Integer(core) = *core {
                    cores.push(core as i32)
                } else {
                    return Err(ErrorKind::ConfigurationError(format!("Could not parse core spec {}", core)).into());
                }
            }
            cores
        }
        None => Vec::with_capacity(0),
        _ => {
            println!("Cores is not an array");
            return Err(ErrorKind::ConfigurationError(String::from("Cores is not an array")).into());
        }
    };

    let strict = match toml.get("strict") {
        Some(&Value::Boolean(l)) => l,
        None => false,
        v => {
            return Err(ErrorKind::ConfigurationError(format!("Could not parse strict spec (should be boolean) {:?}",
                                                             v))
                .into())
        }
    };

    let ports = match toml.get("ports") {
        Some(&Value::Array(ref ports)) => {
            let mut pouts = Vec::with_capacity(ports.len());
            for port in ports {
                let p = try!(read_port(port));
                pouts.push(p);
                // match read_port(port) {
            }
            pouts
        }
        None => Vec::with_capacity(0),
        _ => {
            println!("Ports is not an array");
            return Err(ErrorKind::ConfigurationError(String::from("Ports is not an array")).into());
        }
    };

    Ok(NetbricksConfiguration {
        name: name,
        primary_core: master_lcore,
        cores: cores,
        strict: strict,
        secondary: secondary,
        pool_size: pool_size,
        cache_size: cache_size,
        ports: ports,
    })
}

/// Read a configuration file and create a `NetbricksConfiguration` structure.
/// `filename` should be TOML formatted file.
pub fn read_configuration(filename: &str) -> Result<NetbricksConfiguration> {
    let mut toml_str = String::new();
    let _ = try!{File::open(filename).and_then(|mut f| f.read_to_string(&mut toml_str))
        .chain_err(|| ErrorKind::ConfigurationError(String::from("Could not read file")))};
    read_configuration_from_str(&toml_str[..], filename)
}
<|endoftext|>


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

use crate::{FuzzTarget, FuzzTargetImpl};
use anyhow::{format_err, Result};
use once_cell::sync::Lazy;
use std::{collections::BTreeMap, env};

/// Convenience macro to return the module name.
macro_rules! module_name {
    () => {
        module_path!()
            .rsplit("::")
            .next()
            .expect("module path must have at least one component")
    };
}

/// A fuzz target implementation for protobuf-compiled targets.
macro_rules! proto_fuzz_target {
    ($target:ident => $ty:ty, $prototy:ty) => {
        #[derive(Clone, Debug, Default)]
        pub struct $target;

        impl $crate::FuzzTargetImpl for $target {
            fn name(&self) -> &'static str {
                module_name!()
            }

            fn description(&self) -> &'static str {
                concat!(stringify!($ty), " (protobuf)")
            }

            fn generate(
                &self,
                _idx: usize,
                gen: &mut ::libra_proptest_helpers::ValueGenerator,
            ) -> Option<Vec<u8>> {
                use libra_prost_test_helpers::MessageExt;

                let value: $prototy = gen.generate(::proptest::arbitrary::any::<$ty>()).into();

                Some(value.to_vec().expect("failed to convert to bytes"))
            }

            fn fuzz(&self, data: &[u8]) {
                use prost::Message;
                use std::convert::TryFrom;

                // Errors are OK -- the fuzzer cares about panics and OOMs.
                let _ = <$prototy>::decode(data).map(<$ty>::try_from);
            }
        }
    };
}

// List fuzz target modules here.
mod accumulator_merkle_proof;
mod compiled_module;
mod consensus_proposal;
mod inbound_rpc_protocol;
mod inner_signed_transaction;
mod json_rpc_service;
mod network_noise_initiator;
mod network_noise_responder;
mod signed_transaction;
mod sparse_merkle_proof;
mod storage_save_blocks;
mod storage_schema_decode;
mod vm_value;

static ALL_TARGETS: Lazy<BTreeMap<&'static str, Box<dyn FuzzTargetImpl>>> = Lazy::new(|| {
    let targets: Vec<Box<dyn FuzzTargetImpl>> = vec![
        // List fuzz targets here in this format.
        Box::new(compiled_module::CompiledModuleTarget::default()),
        Box::new(consensus_proposal::ConsensusProposal::default()),
        Box::new(inbound_rpc_protocol::RpcInboundRequest::default()),
        Box::new(inner_signed_transaction::SignedTransactionTarget::default()),
        Box::new(json_rpc_service::JsonRpcSubmitTransactionRequest::default()),
        Box::new(network_noise_initiator::NetworkNoiseInitiator::default()),
        Box::new(network_noise_responder::NetworkNoiseResponder::default()),
        Box::new(signed_transaction::SignedTransactionTarget::default()),
        Box::new(sparse_merkle_proof::SparseMerkleProofTarget::default()),
        Box::new(storage_save_blocks::StorageSaveBlocks::default()),
        Box::new(storage_schema_decode::StorageSchemaDecode::default()),
        Box::new(vm_value::ValueTarget::default()),
    ];
    targets
        .into_iter()
        .map(|target| (target.name(), target))
        .collect()
});

impl FuzzTarget {
    /// The environment variable used for passing fuzz targets to child processes.
    pub(crate) const ENV_VAR: &'static str = "FUZZ_TARGET";

    /// Get the current fuzz target from the environment.
    pub fn from_env() -> Result<Self> {
        let name = env::var(Self::ENV_VAR)?;
        Self::by_name(&name).ok_or_else(|| format_err!("Unknown fuzz target '{}'", name))
    }

    /// Get a fuzz target by name.
    pub fn by_name(name: &str) -> Option<Self> {
        ALL_TARGETS.get(name).map(|target| FuzzTarget(&**target))
    }

    /// A list of all fuzz targets.
    pub fn all_targets() -> impl Iterator<Item = Self> {
        ALL_TARGETS.values().map(|target| FuzzTarget(&**target))
    }
}
<commit_msg>[fuzzing] temporarily removing storage_save_blocks fuzzer due to low exec/s<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{FuzzTarget, FuzzTargetImpl};
use anyhow::{format_err, Result};
use once_cell::sync::Lazy;
use std::{collections::BTreeMap, env};

/// Convenience macro to return the module name.
macro_rules! module_name {
    () => {
        module_path!()
            .rsplit("::")
            .next()
            .expect("module path must have at least one component")
    };
}

/// A fuzz target implementation for protobuf-compiled targets.
macro_rules! proto_fuzz_target {
    ($target:ident => $ty:ty, $prototy:ty) => {
        #[derive(Clone, Debug, Default)]
        pub struct $target;

        impl $crate::FuzzTargetImpl for $target {
            fn name(&self) -> &'static str {
                module_name!()
            }

            fn description(&self) -> &'static str {
                concat!(stringify!($ty), " (protobuf)")
            }

            fn generate(
                &self,
                _idx: usize,
                gen: &mut ::libra_proptest_helpers::ValueGenerator,
            ) -> Option<Vec<u8>> {
                use libra_prost_test_helpers::MessageExt;

                let value: $prototy = gen.generate(::proptest::arbitrary::any::<$ty>()).into();

                Some(value.to_vec().expect("failed to convert to bytes"))
            }

            fn fuzz(&self, data: &[u8]) {
                use prost::Message;
                use std::convert::TryFrom;

                // Errors are OK -- the fuzzer cares about panics and OOMs.
                let _ = <$prototy>::decode(data).map(<$ty>::try_from);
            }
        }
    };
}

// List fuzz target modules here.
mod accumulator_merkle_proof;
mod compiled_module;
mod consensus_proposal;
mod inbound_rpc_protocol;
mod inner_signed_transaction;
mod json_rpc_service;
mod network_noise_initiator;
mod network_noise_responder;
mod signed_transaction;
mod sparse_merkle_proof;
//mod storage_save_blocks;
mod storage_schema_decode;
mod vm_value;

static ALL_TARGETS: Lazy<BTreeMap<&'static str, Box<dyn FuzzTargetImpl>>> = Lazy::new(|| {
    let targets: Vec<Box<dyn FuzzTargetImpl>> = vec![
        // List fuzz targets here in this format.
        Box::new(compiled_module::CompiledModuleTarget::default()),
        Box::new(consensus_proposal::ConsensusProposal::default()),
        Box::new(inbound_rpc_protocol::RpcInboundRequest::default()),
        Box::new(inner_signed_transaction::SignedTransactionTarget::default()),
        Box::new(json_rpc_service::JsonRpcSubmitTransactionRequest::default()),
        Box::new(network_noise_initiator::NetworkNoiseInitiator::default()),
        Box::new(network_noise_responder::NetworkNoiseResponder::default()),
        Box::new(signed_transaction::SignedTransactionTarget::default()),
        Box::new(sparse_merkle_proof::SparseMerkleProofTarget::default()),
        //        Box::new(storage_save_blocks::StorageSaveBlocks::default()),
        Box::new(storage_schema_decode::StorageSchemaDecode::default()),
        Box::new(vm_value::ValueTarget::default()),
    ];
    targets
        .into_iter()
        .map(|target| (target.name(), target))
        .collect()
});

impl FuzzTarget {
    /// The environment variable used for passing fuzz targets to child processes.
    pub(crate) const ENV_VAR: &'static str = "FUZZ_TARGET";

    /// Get the current fuzz target from the environment.
    pub fn from_env() -> Result<Self> {
        let name = env::var(Self::ENV_VAR)?;
        Self::by_name(&name).ok_or_else(|| format_err!("Unknown fuzz target '{}'", name))
    }

    /// Get a fuzz target by name.
    pub fn by_name(name: &str) -> Option<Self> {
        ALL_TARGETS.get(name).map(|target| FuzzTarget(&**target))
    }

    /// A list of all fuzz targets.
    pub fn all_targets() -> impl Iterator<Item = Self> {
        ALL_TARGETS.values().map(|target| FuzzTarget(&**target))
    }
}
<|endoftext|>


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

use crate as dl;
use std::fmt;
use tracing as tr;
use tracing_subscriber::{layer::Context, Layer};

/// A layer that translates tracing events into diem-logger events.
pub struct TracingToDiemLoggerLayer;

fn translate_level(level: &tr::Level) -> Option<dl::Level> {
    if *level == tr::Level::ERROR {
        return Some(dl::Level::Error);
    }
    if *level == tr::Level::INFO {
        return Some(dl::Level::Info);
    }
    if *level == tr::Level::DEBUG {
        return Some(dl::Level::Debug);
    }
    if *level == tr::Level::TRACE {
        return Some(dl::Level::Trace);
    }
    if *level == tr::Level::WARN {
        return Some(dl::Level::Warn);
    }
    None
}

fn translate_metadata(metadata: &tr::Metadata<'static>) -> Option<dl::Metadata> {
    let level = translate_level(metadata.level())?;

    Some(dl::Metadata::new(
        level,
        metadata.target(),
        metadata.module_path().unwrap_or(""),
        metadata.file().unwrap_or(""),
        metadata.line().unwrap_or(0),
        "",
    ))
}

struct KeyValueVisitorAdapter<'a> {
    visitor: &'a mut dyn dl::Visitor,
}

impl<'a> tr::field::Visit for KeyValueVisitorAdapter<'a> {
    fn record_debug(&mut self, field: &tr::field::Field, value: &dyn fmt::Debug) {
        self.visitor
            .visit_pair(dl::Key::new(field.name()), dl::Value::Debug(value))
    }
}

struct EventKeyValueAdapter<'a, 'b> {
    event: &'a tr::Event<'b>,
}

impl<'a, 'b> dl::Schema for EventKeyValueAdapter<'a, 'b> {
    fn visit(&self, visitor: &mut dyn dl::Visitor) {
        self.event.record(&mut KeyValueVisitorAdapter { visitor })
    }
}

impl<S: tr::Subscriber> Layer<S> for TracingToDiemLoggerLayer {
    fn on_event(&self, event: &tr::Event, _ctx: Context<S>) {
        let metadata = match translate_metadata(event.metadata()) {
            Some(metadata) => metadata,
            None => {
                dl::warn!(
                    "[tracing-to-diem-logger] failed to translate event due to unknown level {:?}",
                    event.metadata().level()
                );
                return;
            }
        };

        // `tracing::Event` contains an implicit field named "message".
        // However I couldn't figure out a way to convert it to `fmt::Arguments` due to lifetime issues.
        // Therefore I'm omitting message argument to `Event::dispatch`.
        // This should generally be fine since the message will be translated as a normal record.
        dl::Event::dispatch(&metadata, None, &[&EventKeyValueAdapter { event }]);
    }
}
<commit_msg>logger: check if an event is enabled before dispatching in tracing adapter<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate as dl;
use std::fmt;
use tracing as tr;
use tracing_subscriber::{layer::Context, Layer};

/// A layer that translates tracing events into diem-logger events.
pub struct TracingToDiemLoggerLayer;

fn translate_level(level: &tr::Level) -> Option<dl::Level> {
    if *level == tr::Level::ERROR {
        return Some(dl::Level::Error);
    }
    if *level == tr::Level::INFO {
        return Some(dl::Level::Info);
    }
    if *level == tr::Level::DEBUG {
        return Some(dl::Level::Debug);
    }
    if *level == tr::Level::TRACE {
        return Some(dl::Level::Trace);
    }
    if *level == tr::Level::WARN {
        return Some(dl::Level::Warn);
    }
    None
}

fn translate_metadata(metadata: &tr::Metadata<'static>) -> Option<dl::Metadata> {
    let level = translate_level(metadata.level())?;

    Some(dl::Metadata::new(
        level,
        metadata.target(),
        metadata.module_path().unwrap_or(""),
        metadata.file().unwrap_or(""),
        metadata.line().unwrap_or(0),
        "",
    ))
}

struct KeyValueVisitorAdapter<'a> {
    visitor: &'a mut dyn dl::Visitor,
}

impl<'a> tr::field::Visit for KeyValueVisitorAdapter<'a> {
    fn record_debug(&mut self, field: &tr::field::Field, value: &dyn fmt::Debug) {
        self.visitor
            .visit_pair(dl::Key::new(field.name()), dl::Value::Debug(value))
    }
}

struct EventKeyValueAdapter<'a, 'b> {
    event: &'a tr::Event<'b>,
}

impl<'a, 'b> dl::Schema for EventKeyValueAdapter<'a, 'b> {
    fn visit(&self, visitor: &mut dyn dl::Visitor) {
        self.event.record(&mut KeyValueVisitorAdapter { visitor })
    }
}

impl<S: tr::Subscriber> Layer<S> for TracingToDiemLoggerLayer {
    fn on_event(&self, event: &tr::Event, _ctx: Context<S>) {
        let metadata = match translate_metadata(event.metadata()) {
            Some(metadata) => metadata,
            None => {
                dl::warn!(
                    "[tracing-to-diem-logger] failed to translate event due to unknown level {:?}",
                    event.metadata().level()
                );
                return;
            }
        };

        // `tracing::Event` contains an implicit field named "message".
        // However I couldn't figure out a way to convert it to `fmt::Arguments` due to lifetime issues.
        // Therefore I'm omitting message argument to `Event::dispatch`.
        // This should generally be fine since the message will be translated as a normal record.
        if dl::logger::enabled(&metadata) {
            dl::Event::dispatch(&metadata, None, &[&EventKeyValueAdapter { event }]);
        }
    }
}
<|endoftext|>