Reduce memcpy case in strip_formatting

This makes the return type of FormattedStringExt::strip_formatting
more meaningful.

Drawbacks:

  In theory, it breaks backward compatbility due to the shape of
FormattedStringExt trait was changed. But I expected it's not the
problem for the most case because it's rare to implement that trait
while using this library.
This commit is contained in:
Eunchong Yu 2018-08-19 10:58:36 +09:00
parent c7c65ef671
commit 4feafc681a

View file

@ -15,18 +15,18 @@ struct Parser {
} }
/// An extension trait giving strings a function to strip IRC colors /// An extension trait giving strings a function to strip IRC colors
pub trait FormattedStringExt { pub trait FormattedStringExt<'a> {
/// Returns true if the string contains color, bold, underline or italics /// Returns true if the string contains color, bold, underline or italics
fn is_formatted(&self) -> bool; fn is_formatted(&self) -> bool;
/// Returns the string with all color, bold, underline and italics stripped /// Returns the string with all color, bold, underline and italics stripped
fn strip_formatting(&self) -> Cow<str>; fn strip_formatting(self) -> Cow<'a, str>;
} }
impl FormattedStringExt for str { impl<'a> FormattedStringExt<'a> for &'a str {
fn is_formatted(&self) -> bool { fn is_formatted(&self) -> bool {
self.contains('\x02') || // bold self.contains('\x02') || // bold
self.contains('\x1F') || // underline self.contains('\x1F') || // underline
@ -35,12 +35,22 @@ impl FormattedStringExt for str {
self.contains('\x03') // color self.contains('\x03') // color
} }
fn strip_formatting(&self) -> Cow<str> { fn strip_formatting(self) -> Cow<'a, str> {
if !self.is_formatted() {
return Cow::Borrowed(self);
}
Cow::Owned(internal::strip_formatting(self))
}
}
mod internal { // to reduce commit diff
use super::*;
pub(super) fn strip_formatting(input: &str) -> String {
let mut parser = Parser { let mut parser = Parser {
state: ParserState::Text, state: ParserState::Text,
}; };
let mut prev: char = '\x00'; let mut prev: char = '\x00';
let result: Cow<str> = self input
.chars() .chars()
.filter(move |cur| { .filter(move |cur| {
let result = match parser.state { let result = match parser.state {
@ -92,25 +102,25 @@ impl FormattedStringExt for str {
prev = *cur; prev = *cur;
return result return result
}) })
.collect(); .collect()
result
} }
} }
impl FormattedStringExt for String { impl FormattedStringExt<'static> for String {
fn is_formatted(&self) -> bool { fn is_formatted(&self) -> bool {
self.as_str().is_formatted() self.as_str().is_formatted()
} }
fn strip_formatting(&self) -> Cow<str> { fn strip_formatting(self) -> Cow<'static, str> {
self.as_str().strip_formatting() if !self.is_formatted() {
return Cow::Owned(self);
}
Cow::Owned(internal::strip_formatting(&self))
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::borrow::Cow;
use proto::colors::FormattedStringExt; use proto::colors::FormattedStringExt;
#[test] #[test]
@ -164,4 +174,13 @@ mod test {
fn test_strip_string_with_digit_after_2digit_color() { fn test_strip_string_with_digit_after_2digit_color() {
assert_eq!("\x031212\x031111\x031010".strip_formatting(), "121110"); assert_eq!("\x031212\x031111\x031010".strip_formatting(), "121110");
} }
#[test]
fn test_strip_no_allocation_for_unformatted_text() {
if let Cow::Borrowed(formatted) = "plain text".strip_formatting() {
assert_eq!(formatted, "plain text");
} else {
panic!("allocation detected");
}
}
} }