use std::ops::Deref;
use std::fmt;
use std::str;
use regex::{Regex, RegexBuilder, Error};
use syntax::Expr;
use thread_local::CachedThreadLocal;
pub struct LazyRegex {
builder: LazyRegexBuilder,
local: CachedThreadLocal<Regex>,
}
impl LazyRegex {
pub fn new(source: &str) -> Result<LazyRegex, Error> {
if let Err(err) = Expr::parse(source) {
return Err(err.into());
}
Ok(LazyRegex {
builder: LazyRegexBuilder::new(source),
local: Default::default(),
})
}
}
impl Deref for LazyRegex {
type Target = Regex;
fn deref(&self) -> &Regex {
self.local.get_or(||
Box::new(RegexBuilder::new(&self.builder.source)
.case_insensitive(self.builder.case_insensitive)
.multi_line(self.builder.multi_line)
.dot_matches_new_line(self.builder.dot_matches_new_line)
.swap_greed(self.builder.swap_greed)
.ignore_whitespace(self.builder.ignore_whitespace)
.unicode(self.builder.unicode)
.size_limit(self.builder.size_limit)
.dfa_size_limit(self.builder.dfa_size_limit)
.build().unwrap()))
}
}
impl Clone for LazyRegex {
fn clone(&self) -> LazyRegex {
LazyRegex {
builder: self.builder.clone(),
local: Default::default(),
}
}
}
impl fmt::Debug for LazyRegex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl fmt::Display for LazyRegex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl str::FromStr for LazyRegex {
type Err = Error;
fn from_str(s: &str) -> Result<LazyRegex, Error> {
LazyRegex::new(s)
}
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct LazyRegexBuilder {
source: String,
case_insensitive: bool,
multi_line: bool,
dot_matches_new_line: bool,
swap_greed: bool,
ignore_whitespace: bool,
unicode: bool,
size_limit: usize,
dfa_size_limit: usize,
}
impl Default for LazyRegexBuilder {
fn default() -> Self {
LazyRegexBuilder {
source: "".into(),
case_insensitive: false,
multi_line: false,
dot_matches_new_line: false,
swap_greed: false,
ignore_whitespace: false,
unicode: true,
size_limit: 10 * (1 << 20),
dfa_size_limit: 2 * (1 << 20),
}
}
}
impl LazyRegexBuilder {
pub fn new(source: &str) -> LazyRegexBuilder {
LazyRegexBuilder {
source: source.to_owned(),
.. Default::default()
}
}
pub fn build(&self) -> Result<LazyRegex, Error> {
if let Err(err) = Expr::parse(&self.source) {
return Err(err.into());
}
Ok(LazyRegex {
builder: self.clone(),
local: Default::default(),
})
}
pub fn case_insensitive(&mut self, yes: bool) -> &mut LazyRegexBuilder {
self.case_insensitive = yes;
self
}
pub fn multi_line(&mut self, yes: bool) -> &mut LazyRegexBuilder {
self.multi_line = yes;
self
}
pub fn dot_matches_new_line(&mut self, yes: bool) -> &mut LazyRegexBuilder {
self.dot_matches_new_line = yes;
self
}
pub fn swap_greed(&mut self, yes: bool) -> &mut LazyRegexBuilder {
self.swap_greed = yes;
self
}
pub fn ignore_whitespace(&mut self, yes: bool) -> &mut LazyRegexBuilder {
self.ignore_whitespace = yes;
self
}
pub fn unicode(&mut self, yes: bool) -> &mut LazyRegexBuilder {
self.unicode = yes;
self
}
pub fn size_limit(&mut self, limit: usize) -> &mut LazyRegexBuilder {
self.size_limit = limit;
self
}
pub fn dfa_size_limit(&mut self, limit: usize) -> &mut LazyRegexBuilder {
self.dfa_size_limit = limit;
self
}
}