use crate::IsNone;
use regex::Regex;
use std::borrow::Cow;
lazy_static! {
static ref CONTAINS_WHITESPACE: Regex = Regex::new(r"\s+").unwrap();
}
impl IsNone for String {
fn is_none(&self) -> bool {
self.is_empty()
}
}
impl<'a> IsNone for Cow<'a, str> {
fn is_none(&self) -> bool {
self.is_empty()
}
}
pub trait PruneTrim {
fn prune_trim(self) -> Self;
}
pub trait PruneTrimStart {
fn prune_trim_start(self) -> Self;
}
pub trait PruneTrimEnd {
fn prune_trim_end(self) -> Self;
}
pub trait PruneNoWhitespace {
fn prune_no_whitespace(self) -> Self;
}
impl PruneTrim for String {
fn prune_trim(self) -> Self {
let s = self.trim();
if s != self {
return s.to_owned();
}
self
}
}
impl<'a> PruneTrim for Cow<'a, str> {
fn prune_trim(self) -> Self {
let s = self.trim();
if s != self {
return Cow::Owned(s.to_owned());
}
self
}
}
impl<T> PruneTrim for Option<T>
where
T: PruneTrim + IsNone,
{
fn prune_trim(self) -> Self {
match self {
None => None,
Some(s) => {
let s = s.prune_trim();
if s.is_none() {
None
} else {
Some(s)
}
}
}
}
}
impl<T> PruneTrim for Vec<T>
where
T: PruneTrim,
{
fn prune_trim(self) -> Self {
self.into_iter().map(PruneTrim::prune_trim).collect()
}
}
impl PruneTrimStart for String {
fn prune_trim_start(self) -> Self {
let s = self.trim_start();
if s != self {
return s.to_owned();
}
self
}
}
impl<'a> PruneTrimStart for Cow<'a, str> {
fn prune_trim_start(self) -> Self {
let s = self.trim_start();
if s != self {
return Cow::Owned(s.to_owned());
}
self
}
}
impl<T> PruneTrimStart for Option<T>
where
T: PruneTrimStart + IsNone,
{
fn prune_trim_start(self) -> Self {
match self {
None => None,
Some(s) => {
let s = s.prune_trim_start();
if s.is_none() {
None
} else {
Some(s)
}
}
}
}
}
impl<T> PruneTrimStart for Vec<T>
where
T: PruneTrimStart,
{
fn prune_trim_start(self) -> Self {
self.into_iter()
.map(PruneTrimStart::prune_trim_start)
.collect()
}
}
impl PruneTrimEnd for String {
fn prune_trim_end(self) -> Self {
let s = self.trim_end();
if s != self {
return s.to_owned();
}
self
}
}
impl<'a> PruneTrimEnd for Cow<'a, str> {
fn prune_trim_end(self) -> Self {
let s = self.trim_end();
if s != self {
return Cow::Owned(s.to_owned());
}
self
}
}
impl<T> PruneTrimEnd for Option<T>
where
T: PruneTrimEnd + IsNone,
{
fn prune_trim_end(self) -> Self {
match self {
None => None,
Some(s) => {
let s = s.prune_trim_end();
if s.is_none() {
None
} else {
Some(s)
}
}
}
}
}
impl<T> PruneTrimEnd for Vec<T>
where
T: PruneTrimEnd,
{
fn prune_trim_end(self) -> Self {
self.into_iter().map(PruneTrimEnd::prune_trim_end).collect()
}
}
impl PruneNoWhitespace for String {
fn prune_no_whitespace(self) -> Self {
let s = CONTAINS_WHITESPACE.replace_all(&self, "");
if s != self {
return s.into_owned();
}
self
}
}
impl<'a> PruneNoWhitespace for Cow<'a, str> {
fn prune_no_whitespace(self) -> Self {
let s = CONTAINS_WHITESPACE.replace_all(&self, "");
if s != self {
return Cow::Owned(s.into_owned());
}
self
}
}
impl<T> PruneNoWhitespace for Option<T>
where
T: PruneNoWhitespace + IsNone,
{
fn prune_no_whitespace(self) -> Self {
match self {
None => None,
Some(s) => {
let s = s.prune_no_whitespace();
if s.is_none() {
None
} else {
Some(s)
}
}
}
}
}
impl<T> PruneNoWhitespace for Vec<T>
where
T: PruneNoWhitespace,
{
fn prune_no_whitespace(self) -> Self {
self.into_iter()
.map(PruneNoWhitespace::prune_no_whitespace)
.collect()
}
}
macro_rules! tuple_impls {
($(
($(($idx:tt)),+)
)+) => {
tuple_impls! {
$(
($((T, $idx)),+)
)+
}
};
($(
($(($T:ident, $idx:tt)),+)
)+) => {
$(
impl<T> PruneTrim for ($($T),+) where T: PruneTrim {
fn prune_trim(self) -> Self {
(
$(self.$idx.prune_trim()),+
)
}
}
impl<T> PruneTrimStart for ($($T),+) where T: PruneTrimStart {
fn prune_trim_start(self) -> Self {
(
$(self.$idx.prune_trim_start()),+
)
}
}
impl<T> PruneTrimEnd for ($($T),+) where T: PruneTrimEnd {
fn prune_trim_end(self) -> Self {
(
$(self.$idx.prune_trim_end()),+
)
}
}
impl<T> PruneNoWhitespace for ($($T),+) where T: PruneNoWhitespace {
fn prune_no_whitespace(self) -> Self {
(
$(self.$idx.prune_no_whitespace()),+
)
}
}
)+
};
}
tuple_impls! {
((0), (1))
((0), (1), (2))
((0), (1), (2), (3))
((0), (1), (2), (3), (4))
((0), (1), (2), (3), (4), (5))
((0), (1), (2), (3), (4), (5), (6))
((0), (1), (2), (3), (4), (5), (6), (7))
((0), (1), (2), (3), (4), (5), (6), (7), (8))
((0), (1), (2), (3), (4), (5), (6), (7), (8), (9))
((0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (10))
((0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11))
((0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12))
}
#[cfg(test)]
mod tests {
extern crate test;
#[bench]
fn bench_prune_trim(b: &mut test::Bencher) {
use super::PruneTrim;
b.iter(|| {
" \n \n tirm some thing \n \t "
.to_owned()
.prune_trim();
});
b.iter(|| {
"tirm some thing".to_owned().prune_trim();
});
}
}