diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a886aa0 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,105 @@ +//! # bird-machine +//! +//! Compile your regular expressions at compile time. +//! +//! ## Example: find a date +//! +//! ```rust +//! use bird_machine::{bird_machine, Machine}; +//! +//! #[bird_machine(r"^\d{4}-\d{2}-\d{2}$")] +//! struct Date; +//! +//! assert!(Date::is_match("2014-01-01")); +//! ``` +//! +//! ## Example: iterating over capture groups +//! +//! ```rust +//! use bird_machine::{bird_machine, Machine}; +//! +//! #[bird_machine(r"(\d{4})-(\d{2})-(\d{2})")] +//! struct Date<'a>(&'a str, &'a str, &'a str); +//! let input = "2012-03-14, 2013-01-01 and 2014-07-05"; +//! let match_info = Date::captures_iter(input) +//! .map(|x: Date| format!("Month: {} Day: {} Year: {}", x.1, x.2, x.0)); +//! let expected = [ +//! "Month: 03 Day: 14 Year: 2012", +//! "Month: 01 Day: 01 Year: 2013", +//! "Month: 07 Day: 05 Year: 2014", +//! ]; +//! for (actual, expected) in match_info.zip(expected) { +//! assert_eq!(actual, expected); +//! } +//! ``` +//! +//! # Example: replacement with named capture groups +//! +//! ```rust +//! use bird_machine::{bird_machine, Machine}; +//! +//! #[bird_machine(r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})")] +//! struct Date<'a> { +//! y: &'a str, +//! m: &'a str, +//! d: &'a str, +//! } +//! let before = "2012-03-14, 2013-01-01 and 2014-07-05"; +//! let after = Date::replace_all(before, "$m/$d/$y"); +//! assert_eq!(after, "03/14/2012, 01/01/2013 and 07/05/2014"); +//! ``` +//! +//! # Example: compile-time rejection of invalid regular expressions +//! +//! ```rust,compile_fail +//! use bird_machine::bird_machine; +//! +//! #[bird_machine(r"(oops i left this group open")] +//! struct Bad; +//! ``` +use std::borrow::Cow; + +pub use regex::Match; + +pub use bird_machine_macros::bird_machine; + +pub trait Machine<'t>: Sized { + const ORIGINAL_REGEX: &'static str; + + fn captures(text: &'t str) -> Option<Self>; + + // rust smdh why can this not just return impl Iterator + type CaptureIterator: Iterator<Item = Self>; + fn captures_iter(text: &'t str) -> Self::CaptureIterator; + + fn find(text: &'t str) -> Option<Match<'t>>; + fn find_at(text: &'t str, start: usize) -> Option<Match<'t>>; + + // once again i am asking why trait methods can't return impl Iterator + type FindIterator: Iterator<Item = Match<'t>>; + fn find_iter(text: &'t str) -> Self::FindIterator; + + fn is_match(text: &'t str) -> bool; + fn is_match_at(text: &'t str, start: usize) -> bool; + + fn replace(text: &'t str, rep: impl Replacer<'t, Self>) -> Cow<'t, str>; + fn replace_all(text: &'t str, rep: impl Replacer<'t, Self>) -> Cow<'t, str>; + fn replacen(text: &'t str, limit: usize, rep: impl Replacer<'t, Self>) -> Cow<'t, str>; + + type SplitIterator: Iterator<Item = &'t str>; + fn split(text: &'t str) -> Self::SplitIterator; + type SplitNIterator: Iterator<Item = &'t str>; + fn splitn(text: &'t str, limit: usize) -> Self::SplitNIterator; +} + +pub trait Replacer<'t, M: Machine<'t>> { + fn replace_append(&mut self, r#match: &M, dst: &mut String); +} + +impl<'t, M: Machine<'t>, S: AsRef<str>, F: FnMut(&M) -> S> Replacer<'t, M> for F { + fn replace_append(&mut self, r#match: &M, dst: &mut String) { + let replaced_with = self(r#match); + let replaced_with: &str = replaced_with.as_ref(); + dst.push_str(replaced_with); + } +} |