aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-03-31 23:04:09 -0600
committerMelody Horn <melody@boringcactus.com>2021-03-31 23:04:09 -0600
commit24207feb7726bd2db97693eb8fdd155d33612574 (patch)
treeaa0ee9c2deb20105db7239c2de75593f8b25256f /src
downloadbird-machine-24207feb7726bd2db97693eb8fdd155d33612574.tar.gz
bird-machine-24207feb7726bd2db97693eb8fdd155d33612574.zip
basic sketch of general vibe
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs105
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);
+ }
+}