diff --git a/Cargo.toml b/Cargo.toml index 20ff26e..94615de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,12 +26,11 @@ bench = false [dependencies] cfg-if = "0.1" memchr = { version = "2", default-features = false } -# TODO - move to a non-specific-nightly-version-linked core io alternative -core_io = { version = "0.1.20180307", optional = true, default-features = false, features = ["collections"] } [dev-dependencies] csv = "1.0.0-beta.5" docopt = "0.8" +hashmap_core = "0.1" memmap = "0.6" quickcheck = { version = "0.6", default-features = false } serde = "1" @@ -39,9 +38,9 @@ serde_derive = "1" [features] -default = ["use_std"] -use_std = ["memchr/use_std", "memchr/libc"] -alloc = ["core_io"] +default = ["std"] +std = ["memchr/use_std", "memchr/libc"] +alloc = [] [[bench]] name = "bench" diff --git a/examples/dict-search.rs b/examples/dict-search.rs index 94787f4..064292f 100644 --- a/examples/dict-search.rs +++ b/examples/dict-search.rs @@ -8,15 +8,22 @@ extern crate memmap; extern crate serde; #[macro_use] extern crate serde_derive; +#[macro_use] +extern crate cfg_if; +cfg_if! { + if #[cfg(feature = "std")] { + use std::fs::File; + use std::io::BufRead; + use aho_corasick::{Automaton, AcAutomaton, Match}; + use memmap::Mmap; + } +} use std::error::Error; -use std::fs::File; -use std::io::{self, BufRead, Write}; +use std::io::{self, Write}; use std::process; -use aho_corasick::{Automaton, AcAutomaton, Match}; use docopt::Docopt; -use memmap::Mmap; static USAGE: &'static str = " Usage: dict-search [options] @@ -58,12 +65,12 @@ fn main() { } } } -#[cfg(not(feature = "use_std"))] +#[cfg(not(feature = "std"))] fn run(_: &Args) -> Result<(), Box> { - Err("The use_std feature is mandatory for the dict-search example to work".into()) + Err("The std feature is mandatory for the dict-search example to work".into()) } -#[cfg(feature = "use_std")] +#[cfg(feature = "std")] fn run(args: &Args) -> Result<(), Box> { let aut = try!(build_automaton(&args.flag_dict, args.flag_min_len)); if args.flag_memory_usage { @@ -115,7 +122,7 @@ fn run(args: &Args) -> Result<(), Box> { Ok(()) } -#[cfg(feature = "use_std")] +#[cfg(feature = "std")] fn write_matches(aut: &A, it: I) -> Result<(), Box> where A: Automaton, I: Iterator> { let mut wtr = csv::Writer::from_writer(io::stdout()); @@ -128,7 +135,7 @@ fn write_matches(aut: &A, it: I) -> Result<(), Box> Ok(()) } -#[cfg(feature = "use_std")] +#[cfg(feature = "std")] fn build_automaton( dict_path: &str, min_len: usize, diff --git a/src/autiter.rs b/src/autiter.rs index 9f8bb77..d3c04aa 100644 --- a/src/autiter.rs +++ b/src/autiter.rs @@ -1,15 +1,12 @@ cfg_if! { - - if #[cfg(feature = "use_std")] { + if #[cfg(feature = "std")] { + use std::io::{self, BufRead}; use std::marker::PhantomData; - use std::io::{BufRead, BufReader, Read, Result as IoResult}; } else { use core::marker::PhantomData; - use io::{BufRead, BufReader, Read, Result as IoResult}; } } - use memchr::{memchr, memchr2, memchr3}; use super::{ROOT_STATE, StateIdx}; @@ -86,14 +83,17 @@ pub trait Automaton

{ } /// Returns an iterator of non-overlapping matches in the given reader. - fn stream_find<'a, R: Read>( + /// + /// Only available when the feature flag "std" is present + #[cfg(feature = "std")] + fn stream_find<'a, R: io::Read>( &'a self, rdr: R, ) -> StreamMatches<'a, R, P, Self> where Self: Sized { StreamMatches { aut: self, - buf: BufReader::new(rdr), + buf: io::BufReader::new(rdr), texti: 0, si: ROOT_STATE, _m: PhantomData, @@ -101,14 +101,17 @@ pub trait Automaton

{ } /// Returns an iterator of overlapping matches in the given reader. - fn stream_find_overlapping<'a, R: Read>( + /// + /// Only available when the feature flag "std" is present + #[cfg(feature = "std")] + fn stream_find_overlapping<'a, R: io::Read>( &'a self, rdr: R, ) -> StreamMatchesOverlapping<'a, R, P, Self> where Self: Sized { StreamMatchesOverlapping { aut: self, - buf: BufReader::new(rdr), + buf: io::BufReader::new(rdr), texti: 0, si: ROOT_STATE, outi: 0, @@ -370,20 +373,24 @@ impl<'a, 's, P, A: Automaton

+ ?Sized> Iterator for Matches<'a, 's, P, A> { /// /// `'a` is the lifetime of the automaton, `R` is the type of the underlying /// `io::Read`er, and P is the type of the Automaton's pattern. +/// +/// Only available when the feature flag "std" is present +#[cfg(feature = "std")] #[derive(Debug)] pub struct StreamMatches<'a, R, P, A: 'a + Automaton

+ ?Sized> { aut: &'a A, - buf: BufReader, + buf: io::BufReader, texti: usize, si: StateIdx, _m: PhantomData

, } -impl<'a, R: Read, P, A: Automaton

> +#[cfg(feature = "std")] +impl<'a, R: io::Read, P, A: Automaton

> Iterator for StreamMatches<'a, R, P, A> { - type Item = IoResult; + type Item = io::Result; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { let mut m = None; let mut consumed = 0; 'LOOP: loop { @@ -484,21 +491,25 @@ impl<'a, 's, P, A: Automaton

+ ?Sized> /// /// `'a` is the lifetime of the automaton, `R` is the type of the underlying /// `io::Read`er, and P is the type of the Automaton's pattern. +/// +/// Only available when the feature flag "std" is present +#[cfg(feature = "std")] #[derive(Debug)] pub struct StreamMatchesOverlapping<'a, R, P, A: 'a + Automaton

+ ?Sized> { aut: &'a A, - buf: BufReader, + buf: io::BufReader, texti: usize, si: StateIdx, outi: usize, _m: PhantomData

, } -impl<'a, R: Read, P, A: Automaton

+ ?Sized> +#[cfg(feature = "std")] +impl<'a, R: io::Read, P, A: Automaton

+ ?Sized> Iterator for StreamMatchesOverlapping<'a, R, P, A> { - type Item = IoResult; + type Item = io::Result; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { if self.aut.has_match(self.si, self.outi) { let m = self.aut.get_match(self.si, self.outi, self.texti); self.outi += 1; diff --git a/src/full.rs b/src/full.rs index d962066..a3a2f94 100644 --- a/src/full.rs +++ b/src/full.rs @@ -1,5 +1,5 @@ cfg_if! { - if #[cfg(feature = "use_std")] { + if #[cfg(feature = "std")] { use std::vec::Vec; use std::fmt; use std::mem; diff --git a/src/lib.rs b/src/lib.rs index dbc1409..99036cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,30 +119,30 @@ assert_eq!(matches, vec![Match { pati: 1, start: 0, end: 1}]); */ #![deny(missing_docs)] -#![cfg_attr(not(feature = "use_std"), no_std)] -#![cfg_attr(not(feature = "use_std"), feature(alloc))] -#![cfg_attr(not(feature = "use_std"), feature(slice_concat_ext))] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), feature(alloc))] +#![cfg_attr(not(feature = "std"), feature(slice_concat_ext))] #[macro_use] extern crate cfg_if; -#[cfg(all(test, not(feature = "use_std")))] +#[cfg(all(test, not(feature = "std")))] #[macro_use] extern crate std; -#[cfg(not(feature = "use_std"))] +#[cfg(all(test, not(feature = "std")))] +extern crate hashmap_core; + +#[cfg(not(feature = "std"))] #[macro_use] extern crate alloc; -#[cfg(not(feature = "use_std"))] -extern crate core_io as io; - extern crate memchr; #[cfg(test)] extern crate quickcheck; cfg_if! { - if #[cfg(feature = "use_std")] { + if #[cfg(feature = "std")] { use std::collections::VecDeque; use std::string::String; use std::vec::Vec; @@ -163,7 +163,11 @@ cfg_if! { pub use self::autiter::{ Automaton, Match, - Matches, MatchesOverlapping, StreamMatches, StreamMatchesOverlapping, + Matches, MatchesOverlapping, +}; +#[cfg(feature = "std")] +pub use self::autiter::{ + StreamMatches, StreamMatchesOverlapping }; pub use self::full::FullAcAutomaton; @@ -539,9 +543,9 @@ impl> FromIterator for AcAutomaton { impl + fmt::Debug, T: Transitions> fmt::Debug for AcAutomaton { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[cfg(feature = "use_std")] + #[cfg(feature = "std")] use std::iter::repeat; - #[cfg(not(feature = "use_std"))] + #[cfg(not(feature = "std"))] use core::iter::repeat; try!(writeln!(f, "{}", repeat('-').take(79).collect::())); @@ -560,9 +564,9 @@ impl State { } fn goto_string(&self, root: bool) -> String { - #[cfg(feature = "use_std")] + #[cfg(feature = "std")] use std::char::from_u32; - #[cfg(not(feature = "use_std"))] + #[cfg(not(feature = "std"))] use core::char::from_u32; let mut goto = vec![]; @@ -586,9 +590,9 @@ impl fmt::Debug for State { impl AcAutomaton { #[doc(hidden)] pub fn dot(&self) -> String { - #[cfg(feature = "use_std")] + #[cfg(feature = "std")] use std::fmt::Write; - #[cfg(not(feature = "use_std"))] + #[cfg(not(feature = "std"))] use core::fmt::Write; let mut out = String::new(); macro_rules! w { @@ -635,7 +639,7 @@ fn usize_bytes() -> usize { #[cfg(test)] mod tests { cfg_if! { - if #[cfg(feature = "use_std")] { + if #[cfg(feature = "std")] { use std::boxed::Box; use std::collections::HashSet; use std::string::String; @@ -645,7 +649,7 @@ mod tests { use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; - use io::Cursor; + use hashmap_core::HashSet; } } @@ -658,6 +662,7 @@ mod tests { AcAutomaton::new(xs.to_vec()).find(&haystack).collect() } + #[cfg(feature = "std")] fn aut_finds(xs: &[S], haystack: &str) -> Vec where S: Clone + AsRef<[u8]> { let cur = Cursor::new(haystack.as_bytes()); @@ -670,6 +675,7 @@ mod tests { AcAutomaton::new(xs.to_vec()).into_full().find(haystack).collect() } + #[cfg(feature = "std")] fn aut_findfs(xs: &[S], haystack: &str) -> Vec where S: Clone + AsRef<[u8]> { let cur = Cursor::new(haystack.as_bytes()); @@ -683,6 +689,7 @@ mod tests { AcAutomaton::new(xs.to_vec()).find_overlapping(haystack).collect() } + #[cfg(feature = "std")] fn aut_findos(xs: &[S], haystack: &str) -> Vec where S: Clone + AsRef<[u8]> { let cur = Cursor::new(haystack.as_bytes()); @@ -696,6 +703,7 @@ mod tests { .into_full().find_overlapping(haystack).collect() } + #[cfg(feature = "std")] fn aut_findfos(xs: &[S], haystack: &str) -> Vec where S: Clone + AsRef<[u8]> { let cur = Cursor::new(haystack.as_bytes()); @@ -711,12 +719,27 @@ mod tests { let matches = vec![ Match { pati: 0, start: 1, end: 2 }, ]; + assert_finds_equivalent(ns, hay, matches); + } + + fn assert_finds_equivalent(ns: Vec<&str>, hay: &str, matches: Vec) { assert_eq!(&aut_find(&ns, hay), &matches); + #[cfg(feature = "std")] assert_eq!(&aut_finds(&ns, hay), &matches); assert_eq!(&aut_findf(&ns, hay), &matches); + #[cfg(feature = "std")] assert_eq!(&aut_findfs(&ns, hay), &matches); } + fn assert_overlapping_finds_equivalent(ns: Vec<&str>, hay: &str, matches: Vec) { + assert_eq!(&aut_findo(&ns, hay), &matches); + #[cfg(feature = "std")] + assert_eq!(&aut_findos(&ns, hay), &matches); + assert_eq!(&aut_findfo(&ns, hay), &matches); + #[cfg(feature = "std")] + assert_eq!(&aut_findfos(&ns, hay), &matches); + } + #[test] fn one_pattern_many_match() { let ns = vec!["a"]; @@ -726,10 +749,7 @@ mod tests { Match { pati: 0, start: 3, end: 4 }, Match { pati: 0, start: 8, end: 9 }, ]; - assert_eq!(&aut_find(&ns, hay), &matches); - assert_eq!(&aut_finds(&ns, hay), &matches); - assert_eq!(&aut_findf(&ns, hay), &matches); - assert_eq!(&aut_findfs(&ns, hay), &matches); + assert_finds_equivalent(ns, hay, matches); } #[test] @@ -737,10 +757,7 @@ mod tests { let ns = vec!["abc"]; let hay = "zazabcz"; let matches = vec![ Match { pati: 0, start: 3, end: 6 } ]; - assert_eq!(&aut_find(&ns, hay), &matches); - assert_eq!(&aut_finds(&ns, hay), &matches); - assert_eq!(&aut_findf(&ns, hay), &matches); - assert_eq!(&aut_findfs(&ns, hay), &matches); + assert_finds_equivalent(ns, hay, matches); } #[test] @@ -751,10 +768,7 @@ mod tests { Match { pati: 0, start: 3, end: 6 }, Match { pati: 0, start: 14, end: 17 }, ]; - assert_eq!(&aut_find(&ns, hay), &matches); - assert_eq!(&aut_finds(&ns, hay), &matches); - assert_eq!(&aut_findf(&ns, hay), &matches); - assert_eq!(&aut_findfs(&ns, hay), &matches); + assert_finds_equivalent(ns, hay, matches); } #[test] @@ -762,10 +776,7 @@ mod tests { let ns = vec!["a", "b"]; let hay = "zb"; let matches = vec![ Match { pati: 1, start: 1, end: 2 } ]; - assert_eq!(&aut_find(&ns, hay), &matches); - assert_eq!(&aut_finds(&ns, hay), &matches); - assert_eq!(&aut_findf(&ns, hay), &matches); - assert_eq!(&aut_findfs(&ns, hay), &matches); + assert_finds_equivalent(ns, hay, matches); } #[test] @@ -777,10 +788,7 @@ mod tests { Match { pati: 0, start: 3, end: 4 }, Match { pati: 1, start: 8, end: 9 }, ]; - assert_eq!(&aut_find(&ns, hay), &matches); - assert_eq!(&aut_finds(&ns, hay), &matches); - assert_eq!(&aut_findf(&ns, hay), &matches); - assert_eq!(&aut_findfs(&ns, hay), &matches); + assert_finds_equivalent(ns, hay, matches); } #[test] @@ -788,10 +796,7 @@ mod tests { let ns = vec!["abc", "xyz"]; let hay = "zazxyzz"; let matches = vec![ Match { pati: 1, start: 3, end: 6 } ]; - assert_eq!(&aut_find(&ns, hay), &matches); - assert_eq!(&aut_finds(&ns, hay), &matches); - assert_eq!(&aut_findf(&ns, hay), &matches); - assert_eq!(&aut_findfs(&ns, hay), &matches); + assert_finds_equivalent(ns, hay, matches); } #[test] @@ -803,10 +808,7 @@ mod tests { Match { pati: 0, start: 14, end: 17 }, Match { pati: 1, start: 17, end: 20 }, ]; - assert_eq!(&aut_find(&ns, hay), &matches); - assert_eq!(&aut_finds(&ns, hay), &matches); - assert_eq!(&aut_findf(&ns, hay), &matches); - assert_eq!(&aut_findfs(&ns, hay), &matches); + assert_finds_equivalent(ns, hay, matches); } #[test] @@ -817,10 +819,7 @@ mod tests { Match { pati: 0, start: 3, end: 6 }, Match { pati: 1, start: 4, end: 6 }, ]; - assert_eq!(&aut_findo(&ns, hay), &matches); - assert_eq!(&aut_findos(&ns, hay), &matches); - assert_eq!(&aut_findfo(&ns, hay), &matches); - assert_eq!(&aut_findfos(&ns, hay), &matches); + assert_overlapping_finds_equivalent(ns, hay, matches); } #[test] @@ -828,10 +827,7 @@ mod tests { let ns = vec!["abc", "bc"]; let hay = "xbc"; let matches = vec![ Match { pati: 1, start: 1, end: 3 } ]; - assert_eq!(&aut_findo(&ns, hay), &matches); - assert_eq!(&aut_findos(&ns, hay), &matches); - assert_eq!(&aut_findfo(&ns, hay), &matches); - assert_eq!(&aut_findfos(&ns, hay), &matches); + assert_overlapping_finds_equivalent(ns, hay, matches); } #[test] @@ -846,10 +842,7 @@ mod tests { Match { pati: 2, start: 10, end: 11 }, Match { pati: 2, start: 14, end: 15 }, ]; - assert_eq!(&aut_findo(&ns, hay), &matches); - assert_eq!(&aut_findos(&ns, hay), &matches); - assert_eq!(&aut_findfo(&ns, hay), &matches); - assert_eq!(&aut_findfos(&ns, hay), &matches); + assert_overlapping_finds_equivalent(ns, hay, matches); } #[test] @@ -864,10 +857,7 @@ mod tests { Match { pati: 1, start: 13, end: 15 }, Match { pati: 2, start: 14, end: 15 }, ]; - assert_eq!(&aut_findo(&ns, hay), &matches); - assert_eq!(&aut_findos(&ns, hay), &matches); - assert_eq!(&aut_findfo(&ns, hay), &matches); - assert_eq!(&aut_findfos(&ns, hay), &matches); + assert_overlapping_finds_equivalent(ns, hay, matches); } #[test] @@ -895,10 +885,7 @@ mod tests { fn arbitrary(g: &mut G) -> SmallAscii { use std::char::from_u32; SmallAscii((0..2) - .map(|_| from_u32(g.gen_range(97, 123)).unwrap()) - .collect()) - } - + .map(|_| from_u32(g.gen_range(97, 123)).unwrap()) .collect()) } fn shrink(&self) -> Box> { Box::new(self.0.shrink().map(SmallAscii)) } @@ -962,7 +949,6 @@ mod tests { matches } - #[cfg(feature = "use_std")] #[test] fn qc_ac_equals_naive() { fn prop(needles: Vec, haystack: BiasAscii) -> bool {