<commit_before>use roaring::{RoaringBitmap, Iter};

use std::collections::{BTreeMap, HashMap};
use std::collections::btree_map::Keys;

use search::document::Document;
use search::store::{IndexStore, IndexReader, DocRefIterator};

#[derive(Debug)]
pub struct MemoryIndexStoreFieldTerm {
    pub docs: RoaringBitmap<u64>,
}

impl MemoryIndexStoreFieldTerm {
    pub fn new() -> MemoryIndexStoreFieldTerm {
        MemoryIndexStoreFieldTerm {
            docs: RoaringBitmap::new(),
        }
    }
}

#[derive(Debug)]
pub struct MemoryIndexStoreField {
    pub docs: RoaringBitmap<u64>,
    pub terms: BTreeMap<Vec<u8>, MemoryIndexStoreFieldTerm>,
}

impl MemoryIndexStoreField {
    pub fn new() -> MemoryIndexStoreField {
        MemoryIndexStoreField {
            docs: RoaringBitmap::new(),
            terms: BTreeMap::new(),
        }
    }
}

#[derive(Debug)]
pub struct MemoryIndexStore {
    docs: BTreeMap<u64, Document>,
    fields: BTreeMap<String, MemoryIndexStoreField>,
    next_doc_id: u64,
    doc_key2id_map: HashMap<String, u64>,
}

impl MemoryIndexStore {
    pub fn new() -> MemoryIndexStore {
        MemoryIndexStore {
            docs: BTreeMap::new(),
            fields: BTreeMap::new(),
            next_doc_id: 1,
            doc_key2id_map: HashMap::new(),
        }
    }
}

impl<'a> IndexStore<'a> for MemoryIndexStore {
    type Reader = MemoryIndexStoreReader<'a>;

    fn reader(&'a self) -> MemoryIndexStoreReader<'a> {
        MemoryIndexStoreReader {
            store: self,
        }
    }

    fn insert_or_update_document(&mut self, doc: Document) {
        let doc_id = self.next_doc_id;
        self.next_doc_id += 1;

        // Put field contents in inverted index
        for (field_name, tokens) in doc.fields.iter() {
            let mut position: u32 = 1;

            for token in tokens.iter() {
                if !self.fields.contains_key(field_name) {
                    self.fields.insert(field_name.clone(), MemoryIndexStoreField::new());
                }

                let mut field = self.fields.get_mut(field_name).unwrap();
                field.docs.insert(doc_id);

                let term_bytes = token.term.to_bytes();
                if !field.terms.contains_key(&term_bytes) {
                    // TODO: We shouldn't need to clone here
                    field.terms.insert(term_bytes.clone(), MemoryIndexStoreFieldTerm::new());
                }

                let mut term = field.terms.get_mut(&term_bytes).unwrap();
                term.docs.insert(doc_id);
            }
        }

        self.doc_key2id_map.insert(doc.key.clone(), doc_id);
        self.docs.insert(doc_id, doc);
    }

    fn remove_document_by_key(&mut self, doc_key: &str) -> bool {
        match self.doc_key2id_map.remove(doc_key) {
            Some(doc_id) => {
                self.docs.remove(&doc_id);

                true
            }
            None => false
        }
    }
}

pub struct MemoryIndexStoreReader<'a> {
    store: &'a MemoryIndexStore,
}

impl<'a> IndexReader<'a> for MemoryIndexStoreReader<'a> {
    type AllDocRefIterator = MemoryIndexStoreAllDocRefIterator<'a>;
    type TermDocRefIterator = MemoryIndexStoreTermDocRefIterator<'a>;

    fn get_document_by_key(&self, doc_key: &str) -> Option<&Document> {
        match self.store.doc_key2id_map.get(doc_key) {
            Some(doc_id) => self.store.docs.get(doc_id),
            None => None,
        }
    }

    fn get_document_by_id(&self, doc_id: &u64) -> Option<&Document> {
        self.store.docs.get(doc_id)
    }

    fn contains_document_key(&self, doc_key: &str) -> bool {
        self.store.doc_key2id_map.contains_key(doc_key)
    }

    fn next_doc(&self, term: &[u8], field_name: &str, previous_doc: Option<u64>) -> Option<u64> {
        let field = match self.store.fields.get(field_name) {
            Some(field) => field,
            None => return None,
        };

        let term = match field.terms.get(term) {
            Some(term) => term,
            None => return None,
        };

        match previous_doc {
            Some(previous_doc) => {
                // Find first doc after specified doc
                // TODO: Speed this up (see section 2.1.2 of the IR book)
                for doc_id in term.docs.iter() {
                    if doc_id > previous_doc {
                        return Some(doc_id);
                    }
                }

                // Ran out of docs
                return None;
            }
            None => {
                // Previous doc not specified, return first doc
                match term.docs.iter().next() {
                    Some(doc_id) => Some(doc_id),
                    None => None,
                }
            }
        }
    }

    fn num_docs(&self) -> usize {
        self.store.docs.len()
    }

    fn iter_docids_all(&'a self) -> MemoryIndexStoreAllDocRefIterator<'a> {
        MemoryIndexStoreAllDocRefIterator {
            keys: self.store.docs.keys(),
        }
    }

    fn iter_docids_with_term(&'a self, term: &[u8], field_name: &str) -> Option<MemoryIndexStoreTermDocRefIterator<'a>> {
        let field = match self.store.fields.get(field_name) {
            Some(field) => field,
            None => return None,
        };

        let term = match field.terms.get(term) {
            Some(term) => term,
            None => return None,
        };

        Some(MemoryIndexStoreTermDocRefIterator {
            iterator: term.docs.iter(),
        })
    }

    fn iter_terms(&'a self, field_name: &str) -> Option<Box<Iterator<Item=&'a [u8]> + 'a>> {
        let field = match self.store.fields.get(field_name) {
            Some(field) => field,
            None => return None,
        };

        Some(Box::new(field.terms.keys().map(|t| &t[..])))
    }

    fn term_doc_freq(&'a self, term: &[u8], field_name: &str) -> u64 {
        let field = match self.store.fields.get(field_name) {
            Some(field) => field,
            None => return 0,
        };

        let term = match field.terms.get(term) {
            Some(term) => term,
            None => return 0,
        };

        term.docs.len()
    }

    fn total_tokens(&'a self, field_name: &str) -> u64 {
        let field = match self.store.fields.get(field_name) {
            Some(field) => field,
            None => return 0,
        };

        let mut total_tokens: u64 = 0;
        for (term, postings) in field.terms.iter() {
            total_tokens += postings.docs.len() as u64;
        }

        total_tokens
    }
}

pub struct MemoryIndexStoreAllDocRefIterator<'a> {
    keys: Keys<'a, u64, Document>,
}

impl<'a> Iterator for MemoryIndexStoreAllDocRefIterator<'a> {
    type Item = u64;

    fn next(&mut self) -> Option<u64> {
        self.keys.next().cloned()
    }
}

impl<'a> DocRefIterator<'a> for MemoryIndexStoreAllDocRefIterator<'a> {

}

pub struct MemoryIndexStoreTermDocRefIterator<'a> {
    iterator: Iter<'a, u64>,
}

impl<'a> Iterator for MemoryIndexStoreTermDocRefIterator<'a> {
    type Item = u64;

    fn next(&mut self) -> Option<u64> {
        self.iterator.next()
    }
}

impl<'a> DocRefIterator<'a> for MemoryIndexStoreTermDocRefIterator<'a> {

}

#[cfg(test)]
mod tests {
    use super::{MemoryIndexStore, MemoryIndexStoreReader};

    use search::term::Term;
    use search::analysis::Analyzer;
    use search::document::Document;
    use search::store::{IndexStore, IndexReader};

    fn make_test_store() -> MemoryIndexStore {
        let mut store = MemoryIndexStore::new();

        store.insert_or_update_document(Document {
            key: "test_doc".to_string(),
            fields: btreemap! {
                "title".to_string() => Analyzer::Standard.run("hello world".to_string()),
                "body".to_string() => Analyzer::Standard.run("lorem ipsum dolar".to_string()),
            }
        });

        store.insert_or_update_document(Document {
            key: "test_doc".to_string(),
            fields: btreemap! {
                "title".to_string() => Analyzer::Standard.run("howdy partner".to_string()),
                "body".to_string() => Analyzer::Standard.run("lorem ipsum dolar".to_string()),
            }
        });

        store
    }

    #[test]
    fn test_num_docs() {
        let store = make_test_store();
        let reader = store.reader();

        assert_eq!(reader.num_docs(), 2);
    }

    #[test]
    fn test_all_docs_iterator() {
        let store = make_test_store();
        let reader = store.reader();

        assert_eq!(reader.iter_docids_all().count(), 2);
    }

    #[test]
    fn test_term_docs_iterator() {
        let store = make_test_store();
        let reader = store.reader();

        assert_eq!(reader.iter_docids_with_term(&Term::String("hello".to_string()).to_bytes(), "title").unwrap().count(), 1);
    }
}
<commit_msg>Optimise MemoryIndexStoreReader.total_tokens()<commit_after>use roaring::{RoaringBitmap, Iter};

use std::collections::{BTreeMap, HashMap};
use std::collections::btree_map::Keys;

use search::document::Document;
use search::store::{IndexStore, IndexReader, DocRefIterator};

#[derive(Debug)]
pub struct MemoryIndexStoreFieldTerm {
    pub docs: RoaringBitmap<u64>,
}

impl MemoryIndexStoreFieldTerm {
    pub fn new() -> MemoryIndexStoreFieldTerm {
        MemoryIndexStoreFieldTerm {
            docs: RoaringBitmap::new(),
        }
    }
}

#[derive(Debug)]
pub struct MemoryIndexStoreField {
    pub docs: RoaringBitmap<u64>,
    pub terms: BTreeMap<Vec<u8>, MemoryIndexStoreFieldTerm>,
    pub num_tokens: u64,
}

impl MemoryIndexStoreField {
    pub fn new() -> MemoryIndexStoreField {
        MemoryIndexStoreField {
            docs: RoaringBitmap::new(),
            terms: BTreeMap::new(),
            num_tokens: 0,
        }
    }
}

#[derive(Debug)]
pub struct MemoryIndexStore {
    docs: BTreeMap<u64, Document>,
    fields: BTreeMap<String, MemoryIndexStoreField>,
    next_doc_id: u64,
    doc_key2id_map: HashMap<String, u64>,
}

impl MemoryIndexStore {
    pub fn new() -> MemoryIndexStore {
        MemoryIndexStore {
            docs: BTreeMap::new(),
            fields: BTreeMap::new(),
            next_doc_id: 1,
            doc_key2id_map: HashMap::new(),
        }
    }
}

impl<'a> IndexStore<'a> for MemoryIndexStore {
    type Reader = MemoryIndexStoreReader<'a>;

    fn reader(&'a self) -> MemoryIndexStoreReader<'a> {
        MemoryIndexStoreReader {
            store: self,
        }
    }

    fn insert_or_update_document(&mut self, doc: Document) {
        let doc_id = self.next_doc_id;
        self.next_doc_id += 1;

        // Put field contents in inverted index
        for (field_name, tokens) in doc.fields.iter() {
            let mut position: u32 = 1;

            for token in tokens.iter() {
                if !self.fields.contains_key(field_name) {
                    self.fields.insert(field_name.clone(), MemoryIndexStoreField::new());
                }

                let mut field = self.fields.get_mut(field_name).unwrap();
                field.docs.insert(doc_id);
                field.num_tokens += 1;

                let term_bytes = token.term.to_bytes();
                if !field.terms.contains_key(&term_bytes) {
                    // TODO: We shouldn't need to clone here
                    field.terms.insert(term_bytes.clone(), MemoryIndexStoreFieldTerm::new());
                }

                let mut term = field.terms.get_mut(&term_bytes).unwrap();
                term.docs.insert(doc_id);
            }
        }

        self.doc_key2id_map.insert(doc.key.clone(), doc_id);
        self.docs.insert(doc_id, doc);
    }

    fn remove_document_by_key(&mut self, doc_key: &str) -> bool {
        match self.doc_key2id_map.remove(doc_key) {
            Some(doc_id) => {
                self.docs.remove(&doc_id);

                true
            }
            None => false
        }
    }
}

pub struct MemoryIndexStoreReader<'a> {
    store: &'a MemoryIndexStore,
}

impl<'a> IndexReader<'a> for MemoryIndexStoreReader<'a> {
    type AllDocRefIterator = MemoryIndexStoreAllDocRefIterator<'a>;
    type TermDocRefIterator = MemoryIndexStoreTermDocRefIterator<'a>;

    fn get_document_by_key(&self, doc_key: &str) -> Option<&Document> {
        match self.store.doc_key2id_map.get(doc_key) {
            Some(doc_id) => self.store.docs.get(doc_id),
            None => None,
        }
    }

    fn get_document_by_id(&self, doc_id: &u64) -> Option<&Document> {
        self.store.docs.get(doc_id)
    }

    fn contains_document_key(&self, doc_key: &str) -> bool {
        self.store.doc_key2id_map.contains_key(doc_key)
    }

    fn next_doc(&self, term: &[u8], field_name: &str, previous_doc: Option<u64>) -> Option<u64> {
        let field = match self.store.fields.get(field_name) {
            Some(field) => field,
            None => return None,
        };

        let term = match field.terms.get(term) {
            Some(term) => term,
            None => return None,
        };

        match previous_doc {
            Some(previous_doc) => {
                // Find first doc after specified doc
                // TODO: Speed this up (see section 2.1.2 of the IR book)
                for doc_id in term.docs.iter() {
                    if doc_id > previous_doc {
                        return Some(doc_id);
                    }
                }

                // Ran out of docs
                return None;
            }
            None => {
                // Previous doc not specified, return first doc
                match term.docs.iter().next() {
                    Some(doc_id) => Some(doc_id),
                    None => None,
                }
            }
        }
    }

    fn num_docs(&self) -> usize {
        self.store.docs.len()
    }

    fn iter_docids_all(&'a self) -> MemoryIndexStoreAllDocRefIterator<'a> {
        MemoryIndexStoreAllDocRefIterator {
            keys: self.store.docs.keys(),
        }
    }

    fn iter_docids_with_term(&'a self, term: &[u8], field_name: &str) -> Option<MemoryIndexStoreTermDocRefIterator<'a>> {
        let field = match self.store.fields.get(field_name) {
            Some(field) => field,
            None => return None,
        };

        let term = match field.terms.get(term) {
            Some(term) => term,
            None => return None,
        };

        Some(MemoryIndexStoreTermDocRefIterator {
            iterator: term.docs.iter(),
        })
    }

    fn iter_terms(&'a self, field_name: &str) -> Option<Box<Iterator<Item=&'a [u8]> + 'a>> {
        let field = match self.store.fields.get(field_name) {
            Some(field) => field,
            None => return None,
        };

        Some(Box::new(field.terms.keys().map(|t| &t[..])))
    }

    fn term_doc_freq(&'a self, term: &[u8], field_name: &str) -> u64 {
        let field = match self.store.fields.get(field_name) {
            Some(field) => field,
            None => return 0,
        };

        let term = match field.terms.get(term) {
            Some(term) => term,
            None => return 0,
        };

        term.docs.len()
    }

    fn total_tokens(&'a self, field_name: &str) -> u64 {
        let field = match self.store.fields.get(field_name) {
            Some(field) => field,
            None => return 0,
        };

        field.num_tokens
    }
}

pub struct MemoryIndexStoreAllDocRefIterator<'a> {
    keys: Keys<'a, u64, Document>,
}

impl<'a> Iterator for MemoryIndexStoreAllDocRefIterator<'a> {
    type Item = u64;

    fn next(&mut self) -> Option<u64> {
        self.keys.next().cloned()
    }
}

impl<'a> DocRefIterator<'a> for MemoryIndexStoreAllDocRefIterator<'a> {

}

pub struct MemoryIndexStoreTermDocRefIterator<'a> {
    iterator: Iter<'a, u64>,
}

impl<'a> Iterator for MemoryIndexStoreTermDocRefIterator<'a> {
    type Item = u64;

    fn next(&mut self) -> Option<u64> {
        self.iterator.next()
    }
}

impl<'a> DocRefIterator<'a> for MemoryIndexStoreTermDocRefIterator<'a> {

}

#[cfg(test)]
mod tests {
    use super::{MemoryIndexStore, MemoryIndexStoreReader};

    use search::term::Term;
    use search::analysis::Analyzer;
    use search::document::Document;
    use search::store::{IndexStore, IndexReader};

    fn make_test_store() -> MemoryIndexStore {
        let mut store = MemoryIndexStore::new();

        store.insert_or_update_document(Document {
            key: "test_doc".to_string(),
            fields: btreemap! {
                "title".to_string() => Analyzer::Standard.run("hello world".to_string()),
                "body".to_string() => Analyzer::Standard.run("lorem ipsum dolar".to_string()),
            }
        });

        store.insert_or_update_document(Document {
            key: "test_doc".to_string(),
            fields: btreemap! {
                "title".to_string() => Analyzer::Standard.run("howdy partner".to_string()),
                "body".to_string() => Analyzer::Standard.run("lorem ipsum dolar".to_string()),
            }
        });

        store
    }

    #[test]
    fn test_num_docs() {
        let store = make_test_store();
        let reader = store.reader();

        assert_eq!(reader.num_docs(), 2);
    }

    #[test]
    fn test_all_docs_iterator() {
        let store = make_test_store();
        let reader = store.reader();

        assert_eq!(reader.iter_docids_all().count(), 2);
    }

    #[test]
    fn test_term_docs_iterator() {
        let store = make_test_store();
        let reader = store.reader();

        assert_eq!(reader.iter_docids_with_term(&Term::String("hello".to_string()).to_bytes(), "title").unwrap().count(), 1);
    }
}
<|endoftext|>


<commit_before>use target_info;
use chrono::*;

// Information about the build.
// This information is derived at compile time.

// The file has been placed there by the build.rs script and the 'built' crate.
// Import it privately so we can rename the constants to avoid too deep a nesting.
// TODO: Is there a better way of doing this?
mod bi {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

#[doc="The name of the program."]
pub const PKG_NAME: &'static str = bi::PKG_NAME;

#[doc="The description."]
pub const PKG_DESCRIPTION: &'static str = bi::PKG_DESCRIPTION;

#[doc="The full version."]
pub const PKG_VERSION: &'static str = bi::PKG_VERSION;

#[doc="The major version."]
pub const PKG_VERSION_MAJOR: &'static str = bi::PKG_VERSION_MAJOR;

#[doc="The minor version."]
pub const PKG_VERSION_MINOR: &'static str = bi::PKG_VERSION_MINOR;

#[doc="The patch version."]
pub const PKG_VERSION_PATCH: &'static str = bi::PKG_VERSION_PATCH;

#[doc="The pre-release version."]
pub const PKG_VERSION_PRE: &'static str = bi::PKG_VERSION_PRE;

#[doc="A colon-separated list of authors."]
pub const PKG_AUTHORS: &'static str = bi::PKG_AUTHORS;

#[doc="The homepage."]
pub const PKG_HOMEPAGE: &'static str = bi::PKG_HOMEPAGE;

#[doc="`release` for release builds, `debug` for other builds."]
pub const PROFILE: &'static str = bi::PROFILE;

#[doc="Value of DEBUG for the profile used during compilation."]
pub const DEBUG: bool = bi::DEBUG;

#[doc="Value of OPT_LEVEL for the profile used during compilation."]
pub const OPT_LEVEL: u8 = bi::OPT_LEVEL;

#[doc="The compiler that cargo resolved to use."]
pub const RUSTC: &'static str = bi::RUSTC;

#[doc="The output of `rustc -V`"]
pub const RUSTC_VERSION: &'static str = bi::RUSTC_VERSION;

#[doc="The output of `rustdoc -V`"]
pub const RUSTDOC_VERSION: &'static str = bi::RUSTDOC_VERSION;

#[doc="The documentation generator that cargo resolved to use."]
pub const RUSTDOC: &'static str = bi::RUSTDOC;

#[doc="The features that were enabled during compilation."]
pub const FEATURES: [&'static str; 0] = bi::FEATURES;

#[doc="The features as a comma-separated string."]
pub const FEATURES_STR: &'static str = bi::FEATURES_STR;

#[doc="The built-time in RFC822, UTC."]
pub const BUILD_TIME_UTC: &'static str = bi::BUILT_TIME_UTC;

#[doc="Return BUILD_TIME_UTC as a chrono DateTime<FixedOffset>."]
pub fn build_time() -> DateTime<FixedOffset> {
    DateTime::parse_from_rfc2822(BUILD_TIME_UTC).unwrap()
}

// TODO: These should be compile-time constants too. However, the target_info crate
// only exposes them as functions.
pub fn arch() -> &'static str {
    target_info::Target::arch()
}

pub fn endian() -> &'static str {
    target_info::Target::endian()
}

pub fn env() -> &'static str {
    target_info::Target::env()
}

pub fn family() -> &'static str {
    target_info::Target::family()
}

pub fn os() -> &'static str {
    target_info::Target::os()
}

pub fn log_build_info() {
    info!(r#"BuildInfo {{ PKG_VERSION: "{}", PROFILE: "{}", DEBUG: "{}", OPT_LEVEL: "{}", RUSTC: "{}", RUSTC_VERSION: "{}", FEATURES_STR: "{}", BUILD_TIME_UTC: "{}", arch: "{}", endian: "{}", env: "{}", family: "{}", os: "{}" }}"#,
        PKG_VERSION, PROFILE, DEBUG, OPT_LEVEL, RUSTC, RUSTC_VERSION, FEATURES_STR, BUILD_TIME_UTC,
        arch(), endian(), env(), family(), os()
        );
}

macro_rules! return_cfg {
	($i:ident : $s:expr) => ( if cfg!($i = $s) { return $s; } );
	($i:ident : $s:expr, $($t:expr),+) => ( return_cfg!($i: $s); return_cfg!($i: $($t),+) );
}

/*
pub const ARCH: &'static str = {
		return_cfg!(target_arch: "x86", "x86_64", "mips", "powerpc", "arm", "aarch64");
		"unknown"
	};

    // e.g. x86, x86_64, mips...
    pub arch: &'static str,
    // little or big.
    pub endian: &'static str,
    // e.g. gnu, msvc, musl.
    pub env: &'static str,
    // e.g. unix, windows.
    pub family: &'static str,
    // e.g. linux, windows, macos, ios, android.
    pub os: &'static str

*/
<commit_msg>Attempt to simplify build_info. Failed to re-export constants.<commit_after>use target_info;
use chrono::*;

// Information about the build.
// This information is derived at compile time.

// The file has been placed there by the build.rs script and the 'built' crate.
// Import it privately so we can rename the constants to avoid too deep a nesting.
// TODO: Is there a better way of doing this?
mod bi {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

// pub use bi::PKG_NAME;
// pub use bi::PKG_DESCRIPTION;
// pub use bi::PKG_VERSION;
// pub use bi::PKG_VERSION_MAJOR;
// pub use bi::PKG_VERSION_MINOR;
// pub use bi::PKG_VERSION_PATCH;
// pub use bi::PKG_VERSION_PRE;
// pub use bi::PKG_AUTHORS;
// pub use bi::PKG_HOMEPAGE;
// pub use bi::PROFILE;
// pub use bi::DEBUG;
// pub use bi::OPT_LEVEL;
// pub use bi::RUSTC;
// pub use bi::RUSTC_VERSION;
// pub use bi::RUSTDOC;
// pub use bi::RUSTDOC_VERSION;
// pub use bi::FEATURES;
// pub use bi::FEATURES_STR;
// pub use bi::BUILD_TIME_UTC;

#[doc="The name of the program."]
pub const PKG_NAME: &'static str = bi::PKG_NAME;

#[doc="The description."]
pub const PKG_DESCRIPTION: &'static str = bi::PKG_DESCRIPTION;

#[doc="The full version."]
pub const PKG_VERSION: &'static str = bi::PKG_VERSION;

#[doc="The major version."]
pub const PKG_VERSION_MAJOR: &'static str = bi::PKG_VERSION_MAJOR;

#[doc="The minor version."]
pub const PKG_VERSION_MINOR: &'static str = bi::PKG_VERSION_MINOR;

#[doc="The patch version."]
pub const PKG_VERSION_PATCH: &'static str = bi::PKG_VERSION_PATCH;

#[doc="The pre-release version."]
pub const PKG_VERSION_PRE: &'static str = bi::PKG_VERSION_PRE;

#[doc="A colon-separated list of authors."]
pub const PKG_AUTHORS: &'static str = bi::PKG_AUTHORS;

#[doc="The homepage."]
pub const PKG_HOMEPAGE: &'static str = bi::PKG_HOMEPAGE;

#[doc="`release` for release builds, `debug` for other builds."]
pub const PROFILE: &'static str = bi::PROFILE;

#[doc="Value of DEBUG for the profile used during compilation."]
pub const DEBUG: bool = bi::DEBUG;

#[doc="Value of OPT_LEVEL for the profile used during compilation."]
pub const OPT_LEVEL: u8 = bi::OPT_LEVEL;

#[doc="The compiler that cargo resolved to use."]
pub const RUSTC: &'static str = bi::RUSTC;

#[doc="The output of `rustc -V`"]
pub const RUSTC_VERSION: &'static str = bi::RUSTC_VERSION;

#[doc="The output of `rustdoc -V`"]
pub const RUSTDOC_VERSION: &'static str = bi::RUSTDOC_VERSION;

#[doc="The documentation generator that cargo resolved to use."]
pub const RUSTDOC: &'static str = bi::RUSTDOC;

#[doc="The features that were enabled during compilation."]
pub const FEATURES: [&'static str; 0] = bi::FEATURES;

#[doc="The features as a comma-separated string."]
pub const FEATURES_STR: &'static str = bi::FEATURES_STR;

#[doc="The built-time in RFC822, UTC."]
pub const BUILD_TIME_UTC: &'static str = bi::BUILT_TIME_UTC;

#[doc="Return BUILD_TIME_UTC as a chrono DateTime<FixedOffset>."]
pub fn build_time() -> DateTime<FixedOffset> {
    DateTime::parse_from_rfc2822(BUILD_TIME_UTC).unwrap()
}

// TODO: These should be compile-time constants too. However, the target_info crate
// only exposes them as functions.
pub fn arch() -> &'static str {
    target_info::Target::arch()
}

pub fn endian() -> &'static str {
    target_info::Target::endian()
}

pub fn env() -> &'static str {
    target_info::Target::env()
}

pub fn family() -> &'static str {
    target_info::Target::family()
}

pub fn os() -> &'static str {
    target_info::Target::os()
}

pub fn log_build_info() {
    info!(r#"BuildInfo {{ PKG_VERSION: "{}", PROFILE: "{}", DEBUG: "{}", OPT_LEVEL: "{}", RUSTC: "{}", RUSTC_VERSION: "{}", FEATURES_STR: "{}", BUILD_TIME_UTC: "{}", arch: "{}", endian: "{}", env: "{}", family: "{}", os: "{}" }}"#,
        PKG_VERSION, PROFILE, DEBUG, OPT_LEVEL, RUSTC, RUSTC_VERSION, FEATURES_STR, BUILD_TIME_UTC,
        arch(), endian(), env(), family(), os()
        );
}
<|endoftext|>


<commit_before>//! Lints concerned with the grouping of digits with underscores in integral or
//! floating-point literal expressions.

use rustc::lint::*;
use syntax::ast::*;
use syntax_pos;
use utils::{span_help_and_lint, snippet_opt, in_external_macro};

/// **What it does:** Warns if a long integral or floating-point constant does not contain underscores.
///
/// **Why is this bad?** Reading long numbers is difficult without separators.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 61864918973511
/// ```
declare_lint! {
    pub UNREADABLE_LITERAL,
    Warn,
    "long integer literal without underscores"
}

/// **What it does:** Warns if an integral or floating-point constant is grouped inconsistently with underscores.
///
/// **Why is this bad?** Readers may incorrectly interpret inconsistently grouped digits.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 618_64_9189_73_511
/// ```
declare_lint! {
    pub INCONSISTENT_DIGIT_GROUPING,
    Warn,
    "integer literals with digits grouped inconsistently"
}

/// **What it does:** Warns if the digits of an integral or floating-point constant are grouped into groups that
/// are too large.
///
/// **Why is this bad?** Negatively impacts readability.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 6186491_8973511
/// ```
declare_lint! {
    pub LARGE_DIGIT_GROUPS,
    Warn,
    "grouping digits into groups that are too large"
}

#[derive(Copy, Clone)]
pub struct LiteralDigitGrouping;

impl LintPass for LiteralDigitGrouping {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNREADABLE_LITERAL, INCONSISTENT_DIGIT_GROUPING, LARGE_DIGIT_GROUPS)
    }
}

impl EarlyLintPass for LiteralDigitGrouping {
    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if in_external_macro(cx, expr.span) {
            return;
        }

        match expr.node {
            ExprKind::Lit(ref lit) => self.check_lit(cx, lit),
            _ => (),
        }
    }
}

impl LiteralDigitGrouping {
    fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
        // Lint integral literals.
        if_let_chain! {[
            let LitKind::Int(..) = lit.node,
            let Some(src) = snippet_opt(cx, lit.span),
            let Some(firstch) = src.chars().next(),
            char::to_digit(firstch, 10).is_some()
        ], {
            let digits = LiteralDigitGrouping::get_digits(&src, false);

            LiteralDigitGrouping::do_lint(digits, cx, &lit.span);
        }}

        // Lint floating-point literals.
        if_let_chain! {[
            let LitKind::Float(..) = lit.node,
            let Some(src) = snippet_opt(cx, lit.span),
            let Some(firstch) = src.chars().next(),
            char::to_digit(firstch, 10).is_some()
        ], {
            let digits: Vec<&str> = LiteralDigitGrouping::get_digits(&src, true)
                .split_terminator('.')
                .collect();

            // Lint integral and fractional parts separately, and then check consistency of digit
            // groups if both pass.
            if let Some(integral_group_size) = LiteralDigitGrouping::do_lint(digits[0], cx, &lit.span) {
                if digits.len() > 1 {
                    // Lint the fractional part of literal just like integral part, but reversed.
                    let fractional_part = &digits[1].chars().rev().collect::<String>();
                    if let Some(fractional_group_size) = LiteralDigitGrouping::do_lint(fractional_part, cx, &lit.span) {
                        let consistent = match (integral_group_size, fractional_group_size) {
                            // No groups on either side of decimal point - good to go.
                            (0, 0) => true,
                            // Integral part has grouped digits, fractional part does not.
                            (_, 0) => digits[1].len() <= integral_group_size,
                            // Fractional part has grouped digits, integral part does not.
                            (0, _) => digits[0].len() <= fractional_group_size,
                            // Both parts have grouped digits. Groups should be the same size.
                            (_, _) => integral_group_size == fractional_group_size,
                        };

                        if !consistent {
                            span_help_and_lint(cx, INCONSISTENT_DIGIT_GROUPING, lit.span,
                                           "digits grouped inconsistently by underscores",
                                           "consider making each group three or four digits");
                        }
                    }
                }
            }
        }}
    }

    /// Returns the digits of an integral or floating-point literal.
    fn get_digits(lit: &str, float: bool) -> &str {
        // Determine delimiter for radix prefix, if present.
        let mb_r = if lit.starts_with("0x") {
            Some('x')
        } else if lit.starts_with("0b") {
            Some('b')
        } else if lit.starts_with("0o") {
            Some('o')
        } else {
            None
        };

        let has_suffix = !float && (lit.contains('i') || lit.contains('u')) || float && lit.contains('f');

        // Grab part of literal between the radix prefix and type suffix.
        let mut digits = if let Some(r) = mb_r {
            lit.split(|c| c == 'i' || c == 'u' || c == r || (float && c == 'f')).nth(1).unwrap()
        } else {
            lit.split(|c| c == 'i' || c == 'u' || (float && c == 'f')).next().unwrap()
        };

        // If there was an underscore before type suffix, drop it.
        if has_suffix && digits.chars().last().unwrap() == '_' {
            digits = digits.split_at(digits.len() - 1).0;
        }

        digits
    }

    /// Performs lint on `digits` (no decimal point) and returns the group size. `None` is
    /// returned when emitting a warning.
    fn do_lint(digits: &str, cx: &EarlyContext, span: &syntax_pos::Span) -> Option<usize> {
        // Grab underscore indices with respect to the units digit.
        let underscore_positions: Vec<usize> = digits.chars().rev().enumerate()
            .filter_map(|(idx, digit)|
                if digit == '_' {
                    Some(idx)
                } else {
                    None
                })
            .collect();

        if underscore_positions.is_empty() {
            // Check if literal needs underscores.
            if digits.len() > 4 {
                span_help_and_lint(cx, UNREADABLE_LITERAL, *span,
                                   "long literal lacking separators",
                                   "consider using underscores to make literal more readable");
                return None;
            } else {
                return Some(0);
            }
        } else {
            // Check consistency and the sizes of the groups.
            let group_size = underscore_positions[0];
            let consistent = underscore_positions
                .windows(2)
                .all(|ps| ps[1] - ps[0] == group_size + 1)
                // number of digits to the left of the last group cannot be bigger than group size.
                && (digits.len() - underscore_positions.last().unwrap() <= group_size + 1);

            if !consistent {
                span_help_and_lint(cx, INCONSISTENT_DIGIT_GROUPING, *span,
                                   "digits grouped inconsistently by underscores",
                                   "consider making each group three or four digits");
                return None;
            } else if group_size > 4 {
                span_help_and_lint(cx, LARGE_DIGIT_GROUPS, *span,
                                   "digit groups should be smaller",
                                   "consider using groups of three or four digits");
                return None;
            }
            return Some(group_size);
        }
    }
}
<commit_msg>Use if let over match.<commit_after>//! Lints concerned with the grouping of digits with underscores in integral or
//! floating-point literal expressions.

use rustc::lint::*;
use syntax::ast::*;
use syntax_pos;
use utils::{span_help_and_lint, snippet_opt, in_external_macro};

/// **What it does:** Warns if a long integral or floating-point constant does not contain underscores.
///
/// **Why is this bad?** Reading long numbers is difficult without separators.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 61864918973511
/// ```
declare_lint! {
    pub UNREADABLE_LITERAL,
    Warn,
    "long integer literal without underscores"
}

/// **What it does:** Warns if an integral or floating-point constant is grouped inconsistently with underscores.
///
/// **Why is this bad?** Readers may incorrectly interpret inconsistently grouped digits.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 618_64_9189_73_511
/// ```
declare_lint! {
    pub INCONSISTENT_DIGIT_GROUPING,
    Warn,
    "integer literals with digits grouped inconsistently"
}

/// **What it does:** Warns if the digits of an integral or floating-point constant are grouped into groups that
/// are too large.
///
/// **Why is this bad?** Negatively impacts readability.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 6186491_8973511
/// ```
declare_lint! {
    pub LARGE_DIGIT_GROUPS,
    Warn,
    "grouping digits into groups that are too large"
}

#[derive(Copy, Clone)]
pub struct LiteralDigitGrouping;

impl LintPass for LiteralDigitGrouping {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNREADABLE_LITERAL, INCONSISTENT_DIGIT_GROUPING, LARGE_DIGIT_GROUPS)
    }
}

impl EarlyLintPass for LiteralDigitGrouping {
    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if in_external_macro(cx, expr.span) {
            return;
        }

        if let ExprKind::Lit(ref lit) = expr.node {
            self.check_lit(cx, lit)
        }
    }
}

impl LiteralDigitGrouping {
    fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
        // Lint integral literals.
        if_let_chain! {[
            let LitKind::Int(..) = lit.node,
            let Some(src) = snippet_opt(cx, lit.span),
            let Some(firstch) = src.chars().next(),
            char::to_digit(firstch, 10).is_some()
        ], {
            let digits = LiteralDigitGrouping::get_digits(&src, false);

            LiteralDigitGrouping::do_lint(digits, cx, &lit.span);
        }}

        // Lint floating-point literals.
        if_let_chain! {[
            let LitKind::Float(..) = lit.node,
            let Some(src) = snippet_opt(cx, lit.span),
            let Some(firstch) = src.chars().next(),
            char::to_digit(firstch, 10).is_some()
        ], {
            let digits: Vec<&str> = LiteralDigitGrouping::get_digits(&src, true)
                .split_terminator('.')
                .collect();

            // Lint integral and fractional parts separately, and then check consistency of digit
            // groups if both pass.
            if let Some(integral_group_size) = LiteralDigitGrouping::do_lint(digits[0], cx, &lit.span) {
                if digits.len() > 1 {
                    // Lint the fractional part of literal just like integral part, but reversed.
                    let fractional_part = &digits[1].chars().rev().collect::<String>();
                    if let Some(fractional_group_size) = LiteralDigitGrouping::do_lint(fractional_part, cx, &lit.span) {
                        let consistent = match (integral_group_size, fractional_group_size) {
                            // No groups on either side of decimal point - good to go.
                            (0, 0) => true,
                            // Integral part has grouped digits, fractional part does not.
                            (_, 0) => digits[1].len() <= integral_group_size,
                            // Fractional part has grouped digits, integral part does not.
                            (0, _) => digits[0].len() <= fractional_group_size,
                            // Both parts have grouped digits. Groups should be the same size.
                            (_, _) => integral_group_size == fractional_group_size,
                        };

                        if !consistent {
                            span_help_and_lint(cx, INCONSISTENT_DIGIT_GROUPING, lit.span,
                                           "digits grouped inconsistently by underscores",
                                           "consider making each group three or four digits");
                        }
                    }
                }
            }
        }}
    }

    /// Returns the digits of an integral or floating-point literal.
    fn get_digits(lit: &str, float: bool) -> &str {
        // Determine delimiter for radix prefix, if present.
        let mb_r = if lit.starts_with("0x") {
            Some('x')
        } else if lit.starts_with("0b") {
            Some('b')
        } else if lit.starts_with("0o") {
            Some('o')
        } else {
            None
        };

        let has_suffix = !float && (lit.contains('i') || lit.contains('u')) || float && lit.contains('f');

        // Grab part of literal between the radix prefix and type suffix.
        let mut digits = if let Some(r) = mb_r {
            lit.split(|c| c == 'i' || c == 'u' || c == r || (float && c == 'f')).nth(1).unwrap()
        } else {
            lit.split(|c| c == 'i' || c == 'u' || (float && c == 'f')).next().unwrap()
        };

        // If there was an underscore before type suffix, drop it.
        if has_suffix && digits.chars().last().unwrap() == '_' {
            digits = digits.split_at(digits.len() - 1).0;
        }

        digits
    }

    /// Performs lint on `digits` (no decimal point) and returns the group size. `None` is
    /// returned when emitting a warning.
    fn do_lint(digits: &str, cx: &EarlyContext, span: &syntax_pos::Span) -> Option<usize> {
        // Grab underscore indices with respect to the units digit.
        let underscore_positions: Vec<usize> = digits.chars().rev().enumerate()
            .filter_map(|(idx, digit)|
                if digit == '_' {
                    Some(idx)
                } else {
                    None
                })
            .collect();

        if underscore_positions.is_empty() {
            // Check if literal needs underscores.
            if digits.len() > 4 {
                span_help_and_lint(cx, UNREADABLE_LITERAL, *span,
                                   "long literal lacking separators",
                                   "consider using underscores to make literal more readable");
                return None;
            } else {
                return Some(0);
            }
        } else {
            // Check consistency and the sizes of the groups.
            let group_size = underscore_positions[0];
            let consistent = underscore_positions
                .windows(2)
                .all(|ps| ps[1] - ps[0] == group_size + 1)
                // number of digits to the left of the last group cannot be bigger than group size.
                && (digits.len() - underscore_positions.last().unwrap() <= group_size + 1);

            if !consistent {
                span_help_and_lint(cx, INCONSISTENT_DIGIT_GROUPING, *span,
                                   "digits grouped inconsistently by underscores",
                                   "consider making each group three or four digits");
                return None;
            } else if group_size > 4 {
                span_help_and_lint(cx, LARGE_DIGIT_GROUPS, *span,
                                   "digit groups should be smaller",
                                   "consider using groups of three or four digits");
                return None;
            }
            return Some(group_size);
        }
    }
}
<|endoftext|>


<commit_before>#![no_std]
// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

#![cfg_attr(feature = "const_prec_climber", feature(const_fn))]

//! # pest. The Elegant Parser
//!
//! pest is a general purpose parser written in Rust with a focus on accessibility, correctness,
//! and performance. It uses parsing expression grammars (or [PEG]) as input, which are similar in
//! spirit to regular expressions, but which offer the enhanced expressivity needed to parse
//! complex languages.
//!
//! [PEG]: https://en.wikipedia.org/wiki/Parsing_expression_grammar
//!
//! ## Getting started
//!
//! The recommended way to start parsing with pest is to read the official [book].
//!
//! Other helpful resources:
//!
//! * API reference on [docs.rs]
//! * play with grammars and share them on our [fiddle]
//! * leave feedback, ask questions, or greet us on [Gitter]
//!
//! [book]: https://pest-parser.github.io/book
//! [docs.rs]: https://docs.rs/pest
//! [fiddle]: https://pest-parser.github.io/#editor
//! [Gitter]: https://gitter.im/dragostis/pest
//!
//! ## Usage
//!
//! The core of pest is the trait [`Parser`], which provides an interface to the parsing
//! functionality.
//!
//! The accompanying crate `pest_derive` can automatically generate a [`Parser`] from a PEG
//! grammar. Using `pest_derive` is highly encouraged, but it is also possible to implement
//! [`Parser`] manually if required.
//!
//! ## `.pest` files
//!
//! Grammar definitions reside in custom `.pest` files located in the crate `src` directory.
//! Parsers are automatically generated from these files using `#[derive(Parser)]` and a special
//! `#[grammar = "..."]` attribute on a dummy struct.
//!
//! ```ignore
//! #[derive(Parser)]
//! #[grammar = "path/to/my_grammar.pest"] // relative to src
//! struct MyParser;
//! ```
//!
//! The syntax of `.pest` files is documented in the [`pest_derive` crate].
//!
//! ## Inline grammars
//!
//! Grammars can also be inlined by using the `#[grammar_inline = "..."]` attribute.
//!
//! [`Parser`]: trait.Parser.html
//! [`pest_derive` crate]: https://docs.rs/pest_derive/

#![doc(html_root_url = "https://docs.rs/pest")]

extern crate alloc;
extern crate ucd_trie;

#[cfg(feature = "pretty-print")]
extern crate serde;
#[cfg(feature = "pretty-print")]
extern crate serde_json;

use core::fmt::Debug;
use core::hash::Hash;
pub use parser::Parser;
pub use parser_state::{state, Atomicity, Lookahead, MatchDir, ParseResult, ParserState};
pub use position::Position;
pub use span::{Lines, Span};
pub use token::Token;

pub mod error;
pub mod iterators;
mod macros;
mod parser;
mod parser_state;
mod position;
pub mod prec_climber;
mod span;
mod stack;
mod token;
#[doc(hidden)]
pub mod unicode;

/// A trait which parser rules must implement.
///
/// This trait is set up so that any struct that implements all of its required traits will
/// automatically implement this trait as well.
///
/// This is essentially a [trait alias](https://github.com/rust-lang/rfcs/pull/1733). When trait
/// aliases are implemented, this may be replaced by one.
pub trait RuleType: Copy + Debug + Eq + Hash + Ord {}

impl<T: Copy + Debug + Eq + Hash + Ord> RuleType for T {}
<commit_msg>cargo fmt.<commit_after>#![no_std]
// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.
#![cfg_attr(feature = "const_prec_climber", feature(const_fn))]

//! # pest. The Elegant Parser
//!
//! pest is a general purpose parser written in Rust with a focus on accessibility, correctness,
//! and performance. It uses parsing expression grammars (or [PEG]) as input, which are similar in
//! spirit to regular expressions, but which offer the enhanced expressivity needed to parse
//! complex languages.
//!
//! [PEG]: https://en.wikipedia.org/wiki/Parsing_expression_grammar
//!
//! ## Getting started
//!
//! The recommended way to start parsing with pest is to read the official [book].
//!
//! Other helpful resources:
//!
//! * API reference on [docs.rs]
//! * play with grammars and share them on our [fiddle]
//! * leave feedback, ask questions, or greet us on [Gitter]
//!
//! [book]: https://pest-parser.github.io/book
//! [docs.rs]: https://docs.rs/pest
//! [fiddle]: https://pest-parser.github.io/#editor
//! [Gitter]: https://gitter.im/dragostis/pest
//!
//! ## Usage
//!
//! The core of pest is the trait [`Parser`], which provides an interface to the parsing
//! functionality.
//!
//! The accompanying crate `pest_derive` can automatically generate a [`Parser`] from a PEG
//! grammar. Using `pest_derive` is highly encouraged, but it is also possible to implement
//! [`Parser`] manually if required.
//!
//! ## `.pest` files
//!
//! Grammar definitions reside in custom `.pest` files located in the crate `src` directory.
//! Parsers are automatically generated from these files using `#[derive(Parser)]` and a special
//! `#[grammar = "..."]` attribute on a dummy struct.
//!
//! ```ignore
//! #[derive(Parser)]
//! #[grammar = "path/to/my_grammar.pest"] // relative to src
//! struct MyParser;
//! ```
//!
//! The syntax of `.pest` files is documented in the [`pest_derive` crate].
//!
//! ## Inline grammars
//!
//! Grammars can also be inlined by using the `#[grammar_inline = "..."]` attribute.
//!
//! [`Parser`]: trait.Parser.html
//! [`pest_derive` crate]: https://docs.rs/pest_derive/

#![doc(html_root_url = "https://docs.rs/pest")]

extern crate alloc;
extern crate ucd_trie;

#[cfg(feature = "pretty-print")]
extern crate serde;
#[cfg(feature = "pretty-print")]
extern crate serde_json;

use core::fmt::Debug;
use core::hash::Hash;
pub use parser::Parser;
pub use parser_state::{state, Atomicity, Lookahead, MatchDir, ParseResult, ParserState};
pub use position::Position;
pub use span::{Lines, Span};
pub use token::Token;

pub mod error;
pub mod iterators;
mod macros;
mod parser;
mod parser_state;
mod position;
pub mod prec_climber;
mod span;
mod stack;
mod token;
#[doc(hidden)]
pub mod unicode;

/// A trait which parser rules must implement.
///
/// This trait is set up so that any struct that implements all of its required traits will
/// automatically implement this trait as well.
///
/// This is essentially a [trait alias](https://github.com/rust-lang/rfcs/pull/1733). When trait
/// aliases are implemented, this may be replaced by one.
pub trait RuleType: Copy + Debug + Eq + Hash + Ord {}

impl<T: Copy + Debug + Eq + Hash + Ord> RuleType for T {}
<|endoftext|>


<commit_before>/*
 * This file is part of Twig (ported to Rust).
 *
 * For the copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * Position within a raw template.
 *
 * @author Colin Kiegel <kiegel@gmx.de>
 */

/////////////
// imports //
/////////////

//use lexer::error::LexerError;
//use lexer::SyntaxErrorCode;

/////////////
// exports //
/////////////

pub type Position = usize;
pub type Line = usize;

#[derive(Debug)]
pub struct Cursor<'a> {
    pos: Position,   // 0,..
    end: Position,   // 0,..
    lineno: Line,    // 1,..
    template: &'a super::Raw, // TODO switch to pointer or slice
}

#[allow(dead_code)]
impl<'a> Cursor<'a> {
    pub fn new(template: &'a super::Raw) -> Cursor<'a> {
        Cursor {
            end: template.code.chars().count(),
            template: template,
            pos: 0,
            lineno: 1,
        }
    }

    // pub fn move_by_text(&mut self, text: &str) -> Result<(), SyntaxError> {
    //     self.pos += text.chars().count();
    //     self.lineno += text.lines().count();
    //
    //     if self.pos > self.end {
    //         return err!(SyntaxErrorCode::Unknown, "out of range").into();
    //     }
    //
    //     Ok(())
    // }

    /// move the cursor `position` by `increment` and keep track of the `lineno`
    /// # panics
    /// when the `increment` would move the cursor `position` out of range
    pub fn move_by(&mut self, increment: usize) {
        let pos = self.pos + increment;
        if pos > self.end {
            panic!("cursor is out of range");
        }
        self.lineno += self.template.code[self.pos..pos].lines().count();
        self.pos = pos;
    }

    /// moves the cursor to a new position
    ///
    /// # Panics
    /// Panics if `pos` is greater than the template's length.
    pub fn move_to(&mut self, pos: usize) {
        if pos > self.pos {
            // if pos > self.end {
            //     panic!("Cursor::move_to() is out of range")
            // }
            self.lineno += self.template.code[self.pos..pos].lines().count();
        } else {
            self.lineno -= self.template.code[pos..self.pos].lines().count();
        }
        self.pos = pos;
    }

    pub fn move_to_end(&mut self) {
        self.lineno += self.template.code[self.pos..self.end].lines().count();
        self.pos = self.end;
    }

    #[inline]
    pub fn slice_by(&mut self, len: usize) -> &'a str  {
        let pos = self.pos + len;
        self.slice_to(pos)
    }

    #[inline]
    pub fn slice_to_end(&mut self) -> &'a str {
        let pos = self.end;
        self.slice_to(pos)
    }

    pub fn slice_to(&mut self, pos: usize) -> &'a str  {
        let ref slice = &self.template.code[self.pos..pos];
        self.lineno += slice.lines().count();
        self.pos = self.end;

        slice
    }

    pub fn template(&self) -> &super::Raw {
        &self.template
    }

    pub fn tail(&self) -> &'a str {
        &self.template.code[self.pos..]
    }

    pub fn is_eof(&self) -> bool {
        self.pos >= self.end
    }

    pub fn position(&self) -> usize {
        self.pos
    }

    pub fn line(&self) -> usize {
        self.lineno
    }

    pub fn set_line(&mut self, line: usize) {
        self.lineno = line;
    }
}

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

    #[test]
    pub fn new() {
        let tpl = Raw::new("123", "");
        let c_o = Cursor::new(&tpl);
        let c_x = Cursor {
            pos: 0,
            end: 3,
            lineno: 1,
            template: &tpl,
        };

        assert_eq!(c_o.pos, c_x.pos);
        assert_eq!(c_o.end, c_x.end);
        assert_eq!(c_o.lineno, c_x.lineno);
    }
}
<commit_msg>template cursor - fix line counting<commit_after>/*
 * This file is part of Twig (ported to Rust).
 *
 * For the copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * Position within a raw template.
 *
 * @author Colin Kiegel <kiegel@gmx.de>
 */

/////////////
// imports //
/////////////

use std::fmt;
//use lexer::error::LexerError;
//use lexer::SyntaxErrorCode;

/////////////
// exports //
/////////////

pub type Position = usize;
pub type Line = usize;

#[derive(Debug)]
pub struct Cursor<'a> {
    pos: Position,   // 0,..
    end: Position,   // 0,..
    lineno: Line,    // 1,..
    template: &'a super::Raw, // TODO switch to pointer or slice
}

impl<'a> Cursor<'a> {
    #[allow(dead_code)] // only used in test and elsewhere
    pub fn new(template: &'a super::Raw) -> Cursor<'a> {
        Cursor {
            end: template.code.chars().count(),
            template: template,
            pos: 0,
            lineno: 1,
        }
    }

    /// move the cursor `position` by `increment` and keep track of the `lineno`
    ///
    /// `increment` in bytes (not chars)
    ///
    /// # panics
    /// when the `increment` would move the cursor `position` out of range
    pub fn move_by(&mut self, increment: usize) {
        if increment == 0 {
            println!("cursor.move_by 0"); // TODO DEBUG + REMOVE
            return;
        };

        let pos = self.pos + increment;
        if pos > self.end {
            panic!("cursor is out of range");
        }
        self.lineno += self.template.code[self.pos..pos].chars().filter(|c| *c == '\n').count();
        self.pos = pos;
    }

    /// moves the cursor to a new position
    ///
    /// # Panics
    /// Panics if `pos` is greater than the template's length.
    pub fn move_to(&mut self, pos: usize) {
        if pos > self.pos {
            // if pos > self.end {
            //     panic!("Cursor::move_to() is out of range")
            // }
            self.lineno += self.template.code[self.pos..pos].chars().filter(|c| *c == '\n').count();
        } else if pos < self.pos {
            self.lineno -= self.template.code[pos..self.pos].chars().filter(|c| *c == '\n').count();
        }
        self.pos = pos;
    }

    #[inline]
    pub fn slice_by(&mut self, len: usize) -> &'a str  {
        let pos = self.pos + len;
        self.slice_to(pos)
    }

    #[inline]
    pub fn slice_to_end(&mut self) -> &'a str {
        let pos = self.end;
        self.slice_to(pos)
    }

    pub fn slice_to(&mut self, pos: usize) -> &'a str  {
        let ref slice = &self.template.code[self.pos..pos];
        self.lineno += slice.chars().filter(|c| *c == '\n').count();
        self.pos = pos;

        slice
    }

    pub fn _template(&self) -> &super::Raw {
        &self.template
    }

    pub fn tail(&self) -> &'a str {
        &self.template.code[self.pos..]
    }

    pub fn is_eof(&self) -> bool {
        self.pos >= self.end
    }

    pub fn position(&self) -> usize {
        self.pos
    }

    pub fn line(&self) -> usize {
        self.lineno
        // Alternative: self.template.code[0..self.pos].chars().filter(|c| c == '\n').count() + 1;
        // - might be better if called seldomly!
    }

    pub fn column(&self) -> usize { // start counting with `1`
        self.template.code[0..self.pos].chars().rev().take_while(|c| *c != '\n').count() + 1
    }

    pub fn set_line(&mut self, line: usize) {
        self.lineno = line;
    }
}

impl<'a> fmt::Display for Cursor<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "`{filename}` line {line} column {column}",
            filename = self.template.filename(),
            line = self.line(),
            column = self.column())
    }
}

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

    #[test]
    pub fn new() {
        let tpl = Raw::new("123", "");
        let c = Cursor::new(&tpl);

        assert_eq!(c.position(), 0);
        assert_eq!(c.line(), 1);
        assert_eq!(c.template.code, "123");
    }

    #[test]
    pub fn move_by() {
        let tpl = Raw::new("\nline2\n\nline4\n\n\nline7", "");
        let mut c = Cursor::new(&tpl);

        let x = "\nline2\n\nline4".len();
        c.move_by(x);
        assert_eq!(c.position(), x);
        assert_eq!(c.line(), 4);
    }

    #[test]
    pub fn move_to() {
        let tpl = Raw::new("\nline2\n\nline4\n\n\nline7", "");
        let mut c = Cursor::new(&tpl);

        let x = "\nline2".len();
        c.move_to(x);
        assert_eq!(c.position(), x);
        assert_eq!(c.line(), 2);
    }

    #[test]
    pub fn slice_by() {
        let tpl = Raw::new("\nline2\n\nline4\n\n\nline7", "");
        let mut c = Cursor::new(&tpl);

        let x = "\nline2\n\nline4".len();
        c.slice_by(x);
        assert_eq!(c.position(), x);
        assert_eq!(c.line(), 4);
    }

    #[test]
    pub fn slice_to() {
        let tpl = Raw::new("\nline2\n\nline4\n\n\nline7", "");
        let mut c = Cursor::new(&tpl);

        let x = "\nline2".len();
        c.slice_to(x);
        assert_eq!(c.position(), x);
        assert_eq!(c.line(), 2);
    }

    #[test]
    pub fn slice_to_end() {
        let tpl = Raw::new("\nline2\n\nline4\n\n\nline7", "");
        let mut c = Cursor::new(&tpl);

        let x = "\nline2\n\nline4\n\n\nline7".len();
        c.slice_to_end();
        assert_eq!(c.position(), x);
        assert_eq!(c.line(), 7);
    }

    #[test]
    pub fn column() { // start counting with `1`
        let tpl = Raw::new("\nline2\n\nline4\n\n\nline7", "");
        let mut c = Cursor::new(&tpl);

        assert_eq!(c.column(), 1);
        c.move_to("\nline2".len());
        assert_eq!(c.column(), 6);
        c.move_to("\nline2\n\nline4\n\n\nl".len());
        assert_eq!(c.column(), 2);
    }
}
<|endoftext|>


<commit_before>// build-pass (FIXME(62277): should be check-pass)

const C: &str = "abc {}";
static S: &str = "{bla}";

#[allow(unreachable_code)]
fn main() {
    panic!("here's a brace: {"); //~ WARN panic message contains a brace
    std::panic!("another one: }"); //~ WARN panic message contains a brace
    core::panic!("Hello {}"); //~ WARN panic message contains an unused formatting placeholder
    assert!(false, "{:03x} {test} bla");
    //~^ WARN panic message contains unused formatting placeholders
    debug_assert!(false, "{{}} bla"); //~ WARN panic message contains braces
    panic!(C); // No warning (yet)
    panic!(S); // No warning (yet)
    panic!(concat!("{", "}")); //~ WARN panic message contains an unused formatting placeholder
    panic!(concat!("{", "{")); //~ WARN panic message contains braces
}
<commit_msg>Test that panic_fmt lint doesn't trigger for custom panic macro.<commit_after>// build-pass (FIXME(62277): should be check-pass)

const C: &str = "abc {}";
static S: &str = "{bla}";

#[allow(unreachable_code)]
fn main() {
    panic!("here's a brace: {"); //~ WARN panic message contains a brace
    std::panic!("another one: }"); //~ WARN panic message contains a brace
    core::panic!("Hello {}"); //~ WARN panic message contains an unused formatting placeholder
    assert!(false, "{:03x} {test} bla");
    //~^ WARN panic message contains unused formatting placeholders
    debug_assert!(false, "{{}} bla"); //~ WARN panic message contains braces
    panic!(C); // No warning (yet)
    panic!(S); // No warning (yet)
    panic!(concat!("{", "}")); //~ WARN panic message contains an unused formatting placeholder
    panic!(concat!("{", "{")); //~ WARN panic message contains braces

    // Check that the lint only triggers for std::panic and core::panic,
    // not any panic macro:
    macro_rules! panic {
        ($e:expr) => ();
    }
    panic!("{}"); // OK
}
<|endoftext|>


<commit_before>// # Custom collector example
//
// This example shows how you can implement your own
// collector. As an example, we will compute a collector
// that computes the standard deviation of a given fast field.
//
// Of course, you can have a look at the tantivy's built-in collectors
// such as the `CountCollector` for more examples.

// ---
// Importing tantivy...
use std::marker::PhantomData;

use crate::collector::{Collector, SegmentCollector};
use crate::fastfield::FastFieldReader;
use crate::schema::Field;
use crate::{Score, SegmentReader, TantivyError};

/// The `TopDocs` collector keeps track of the top `K` documents
/// sorted by their score.
///
/// The implementation is based on a `BinaryHeap`.
/// The theorical complexity for collecting the top `K` out of `n` documents
/// is `O(n log K)`.
///
/// This collector guarantees a stable sorting in case of a tie on the
/// document score. As such, it is suitable to implement pagination.
///
/// ```rust
/// use tantivy::collector::{TopDocs, FilterCollector};
/// use tantivy::query::QueryParser;
/// use tantivy::schema::{Schema, TEXT, INDEXED, FAST};
/// use tantivy::{doc, DocAddress, Index};
///
/// let mut schema_builder = Schema::builder();
/// let title = schema_builder.add_text_field("title", TEXT);
/// let price = schema_builder.add_u64_field("price", INDEXED | FAST);
/// let schema = schema_builder.build();
/// let index = Index::create_in_ram(schema);
///
/// let mut index_writer = index.writer_with_num_threads(1, 10_000_000).unwrap();
/// index_writer.add_document(doc!(title => "The Name of the Wind", price => 30_200u64));
/// index_writer.add_document(doc!(title => "The Diary of Muadib", price => 29_240u64));
/// index_writer.add_document(doc!(title => "A Dairy Cow", price => 21_240u64));
/// index_writer.add_document(doc!(title => "The Diary of a Young Girl", price => 20_120u64));
/// assert!(index_writer.commit().is_ok());
///
/// let reader = index.reader().unwrap();
/// let searcher = reader.searcher();
///
/// let query_parser = QueryParser::for_index(&index, vec![title]);
/// let query = query_parser.parse_query("diary").unwrap();
/// let no_filter_collector = FilterCollector::new(price, &|value| true, TopDocs::with_limit(2));
/// let top_docs = searcher.search(&query, &no_filter_collector).unwrap();
///
/// assert_eq!(top_docs.len(), 2);
/// assert_eq!(top_docs[0].1, DocAddress(0, 1));
/// assert_eq!(top_docs[1].1, DocAddress(0, 3));
///
/// let filter_all_collector = FilterCollector::new(price, &|value| false, TopDocs::with_limit(2));
/// let filtered_top_docs = searcher.search(&query, &filter_all_collector).unwrap();
///
/// assert_eq!(filtered_top_docs.len(), 0);
/// ```
pub struct FilterCollector<TCollector, TSegmentCollector> {
    field: Field,
    collector: TCollector,
    predicate: &'static (dyn Fn(u64) -> bool + Send + Sync),
    phantom: PhantomData<TSegmentCollector>
}

impl<TCollector, TSegmentCollector> FilterCollector<TCollector, TSegmentCollector>
where
    TCollector: Collector<Child = TSegmentCollector> + Send + Sync,
    TSegmentCollector: SegmentCollector + Send + Sync {
    pub fn new(field: Field, predicate: &'static (dyn Fn(u64) -> bool + Send + Sync), collector: TCollector) -> FilterCollector<TCollector, TSegmentCollector> {
        FilterCollector { field, predicate, collector, phantom: PhantomData }
    }
}

impl<TCollector, TSegmentCollector> Collector for FilterCollector<TCollector, TSegmentCollector>
where
    TSegmentCollector: SegmentCollector + Send + Sync,
    TCollector: Collector<Child = TSegmentCollector> + Send + Sync {
    // That's the type of our result.
    // Our standard deviation will be a float.
    type Fruit = TCollector::Fruit;

    type Child = FilterSegmentCollector<TSegmentCollector>;

    fn for_segment(
        &self,
        segment_local_id: u32,
        segment_reader: &SegmentReader,
    ) -> crate::Result<FilterSegmentCollector<TSegmentCollector>> {
        let fast_field_reader = segment_reader
            .fast_fields()
            .u64(self.field)
            .ok_or_else(|| {
                let field_name = segment_reader.schema().get_field_name(self.field);
                TantivyError::SchemaError(format!(
                    "Field {:?} is not a u64 fast field.",
                    field_name
                ))
            })?;
        let child_segment_collector = self.collector.for_segment(segment_local_id, segment_reader);
        match child_segment_collector {
            Ok(segment_collector) => {
                Ok(FilterSegmentCollector::<TSegmentCollector> {
                    fast_field_reader,
                    segment_collector: segment_collector,
                    predicate: self.predicate
                })
            },
            Err(_) => {
                Err(TantivyError::SystemError("Could not open segment: ".to_owned()))
            },
        }

    }

    fn requires_scoring(&self) -> bool {
        self.collector.requires_scoring()
    }

    fn merge_fruits(&self, segment_fruits: Vec<<TCollector::Child as SegmentCollector>::Fruit>) -> crate::Result<TCollector::Fruit> {
        self.collector.merge_fruits(segment_fruits)
    }
}

pub struct FilterSegmentCollector<TSegmentCollector> {
    fast_field_reader: FastFieldReader<u64>,
    segment_collector: TSegmentCollector,
    predicate: &'static (dyn Fn(u64) -> bool + Send + Sync)
}

impl<TSegmentCollector> SegmentCollector for FilterSegmentCollector<TSegmentCollector>
where
    TSegmentCollector: SegmentCollector + Send + Sync {
    type Fruit = TSegmentCollector::Fruit;

    fn collect(&mut self, doc: u32, score: Score) {
        let value = self.fast_field_reader.get(doc);
        if (self.predicate)(value) {
            self.segment_collector.collect(doc, score)
        }
    }

    fn harvest(self) -> <TSegmentCollector as SegmentCollector>::Fruit {
        self.segment_collector.harvest()
    }
}
<commit_msg>updated docs<commit_after>// # Custom collector example
//
// This example shows how you can implement your own
// collector. As an example, we will compute a collector
// that computes the standard deviation of a given fast field.
//
// Of course, you can have a look at the tantivy's built-in collectors
// such as the `CountCollector` for more examples.

// ---
// Importing tantivy...
use std::marker::PhantomData;

use crate::collector::{Collector, SegmentCollector};
use crate::fastfield::FastFieldReader;
use crate::schema::Field;
use crate::{Score, SegmentReader, TantivyError};

/// The `FilterCollector` collector filters docs using a u64 fast field value and a predicate.
/// Only the documents for which the predicate returned "true" will be passed on to the next collector.
///
/// ```rust
/// use tantivy::collector::{TopDocs, FilterCollector};
/// use tantivy::query::QueryParser;
/// use tantivy::schema::{Schema, TEXT, INDEXED, FAST};
/// use tantivy::{doc, DocAddress, Index};
///
/// let mut schema_builder = Schema::builder();
/// let title = schema_builder.add_text_field("title", TEXT);
/// let price = schema_builder.add_u64_field("price", INDEXED | FAST);
/// let schema = schema_builder.build();
/// let index = Index::create_in_ram(schema);
///
/// let mut index_writer = index.writer_with_num_threads(1, 10_000_000).unwrap();
/// index_writer.add_document(doc!(title => "The Name of the Wind", price => 30_200u64));
/// index_writer.add_document(doc!(title => "The Diary of Muadib", price => 29_240u64));
/// index_writer.add_document(doc!(title => "A Dairy Cow", price => 21_240u64));
/// index_writer.add_document(doc!(title => "The Diary of a Young Girl", price => 20_120u64));
/// assert!(index_writer.commit().is_ok());
///
/// let reader = index.reader().unwrap();
/// let searcher = reader.searcher();
///
/// let query_parser = QueryParser::for_index(&index, vec![title]);
/// let query = query_parser.parse_query("diary").unwrap();
/// let no_filter_collector = FilterCollector::new(price, &|value| true, TopDocs::with_limit(2));
/// let top_docs = searcher.search(&query, &no_filter_collector).unwrap();
///
/// assert_eq!(top_docs.len(), 2);
/// assert_eq!(top_docs[0].1, DocAddress(0, 1));
/// assert_eq!(top_docs[1].1, DocAddress(0, 3));
///
/// let filter_all_collector = FilterCollector::new(price, &|value| false, TopDocs::with_limit(2));
/// let filtered_top_docs = searcher.search(&query, &filter_all_collector).unwrap();
///
/// assert_eq!(filtered_top_docs.len(), 0);
/// ```
pub struct FilterCollector<TCollector, TSegmentCollector> {
    field: Field,
    collector: TCollector,
    predicate: &'static (dyn Fn(u64) -> bool + Send + Sync),
    phantom: PhantomData<TSegmentCollector>
}

impl<TCollector, TSegmentCollector> FilterCollector<TCollector, TSegmentCollector>
where
    TCollector: Collector<Child = TSegmentCollector> + Send + Sync,
    TSegmentCollector: SegmentCollector + Send + Sync {
    pub fn new(field: Field, predicate: &'static (dyn Fn(u64) -> bool + Send + Sync), collector: TCollector) -> FilterCollector<TCollector, TSegmentCollector> {
        FilterCollector { field, predicate, collector, phantom: PhantomData }
    }
}

impl<TCollector, TSegmentCollector> Collector for FilterCollector<TCollector, TSegmentCollector>
where
    TSegmentCollector: SegmentCollector + Send + Sync,
    TCollector: Collector<Child = TSegmentCollector> + Send + Sync {
    // That's the type of our result.
    // Our standard deviation will be a float.
    type Fruit = TCollector::Fruit;

    type Child = FilterSegmentCollector<TSegmentCollector>;

    fn for_segment(
        &self,
        segment_local_id: u32,
        segment_reader: &SegmentReader,
    ) -> crate::Result<FilterSegmentCollector<TSegmentCollector>> {
        let fast_field_reader = segment_reader
            .fast_fields()
            .u64(self.field)
            .ok_or_else(|| {
                let field_name = segment_reader.schema().get_field_name(self.field);
                TantivyError::SchemaError(format!(
                    "Field {:?} is not a u64 fast field.",
                    field_name
                ))
            })?;
        let child_segment_collector = self.collector.for_segment(segment_local_id, segment_reader);
        match child_segment_collector {
            Ok(segment_collector) => {
                Ok(FilterSegmentCollector::<TSegmentCollector> {
                    fast_field_reader,
                    segment_collector: segment_collector,
                    predicate: self.predicate
                })
            },
            Err(_) => {
                Err(TantivyError::SystemError("Could not open segment: ".to_owned()))
            },
        }

    }

    fn requires_scoring(&self) -> bool {
        self.collector.requires_scoring()
    }

    fn merge_fruits(&self, segment_fruits: Vec<<TCollector::Child as SegmentCollector>::Fruit>) -> crate::Result<TCollector::Fruit> {
        self.collector.merge_fruits(segment_fruits)
    }
}

pub struct FilterSegmentCollector<TSegmentCollector> {
    fast_field_reader: FastFieldReader<u64>,
    segment_collector: TSegmentCollector,
    predicate: &'static (dyn Fn(u64) -> bool + Send + Sync)
}

impl<TSegmentCollector> SegmentCollector for FilterSegmentCollector<TSegmentCollector>
where
    TSegmentCollector: SegmentCollector + Send + Sync {
    type Fruit = TSegmentCollector::Fruit;

    fn collect(&mut self, doc: u32, score: Score) {
        let value = self.fast_field_reader.get(doc);
        if (self.predicate)(value) {
            self.segment_collector.collect(doc, score)
        }
    }

    fn harvest(self) -> <TSegmentCollector as SegmentCollector>::Fruit {
        self.segment_collector.harvest()
    }
}
<|endoftext|>


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

// spell-checker: ignore (ToDO) INVS

use std::num::Wrapping;

use crate::Factors;

include!(concat!(env!("OUT_DIR"), "/prime_table.rs"));

pub(crate) fn factor(mut num: u64) -> (Factors, u64) {
    let mut factors = Factors::one();
    for &(prime, inv, ceil) in P_INVS_U64 {
        if num == 1 {
            break;
        }

        // inv = prime^-1 mod 2^64
        // ceil = floor((2^64-1) / prime)
        // if (num * inv) mod 2^64 <= ceil, then prime divides num
        // See https://math.stackexchange.com/questions/1251327/
        // for a nice explanation.
        loop {
            let Wrapping(x) = Wrapping(num) * Wrapping(inv);

            // While prime divides num
            if x <= ceil {
                num = x;
                factors.push(prime);
            } else {
                break;
            }
        }
    }

    (factors, num)
}
<commit_msg>factor::table: Coalesce accesses to the `factors` table<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 kwantam <kwantam@gmail.com>
// * (c) 2020 nicoo   <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

// spell-checker: ignore (ToDO) INVS

use std::num::Wrapping;

use crate::Factors;

include!(concat!(env!("OUT_DIR"), "/prime_table.rs"));

pub(crate) fn factor(mut num: u64) -> (Factors, u64) {
    let mut factors = Factors::one();
    for &(prime, inv, ceil) in P_INVS_U64 {
        if num == 1 {
            break;
        }

        // inv = prime^-1 mod 2^64
        // ceil = floor((2^64-1) / prime)
        // if (num * inv) mod 2^64 <= ceil, then prime divides num
        // See https://math.stackexchange.com/questions/1251327/
        // for a nice explanation.
        let mut k = 0;
        loop {
            let Wrapping(x) = Wrapping(num) * Wrapping(inv);

            // While prime divides num
            if x <= ceil {
                num = x;
                k += 1;
            } else {
                if k > 0 {
                    factors.add(prime, k);
                }
                break;
            }
        }
    }

    (factors, num)
}
<|endoftext|>