summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/eco.rs180
1 files changed, 66 insertions, 114 deletions
diff --git a/src/util/eco.rs b/src/util/eco.rs
index 08c2117d..207f1753 100644
--- a/src/util/eco.rs
+++ b/src/util/eco.rs
@@ -1,14 +1,11 @@
use std::borrow::Borrow;
use std::cmp::Ordering;
-use std::convert::TryFrom;
use std::fmt::{self, Debug, Display, Formatter, Write};
use std::hash::{Hash, Hasher};
-use std::ops::{Add, AddAssign, Deref};
+use std::ops::Deref;
use std::rc::Rc;
-use crate::diag::StrResult;
-
-/// An economical string with inline storage and clone-on-write value semantics.
+/// An economical string with inline storage and clone-on-write semantics.
#[derive(Clone)]
pub struct EcoString(Repr);
@@ -144,75 +141,25 @@ impl EcoString {
}
/// Repeat this string `n` times.
- pub fn repeat(&self, n: i64) -> StrResult<Self> {
- let (n, new) = usize::try_from(n)
- .ok()
- .and_then(|n| self.len().checked_mul(n).map(|new| (n, new)))
- .ok_or_else(|| format!("cannot repeat this string {} times", n))?;
+ pub fn repeat(&self, n: usize) -> Self {
+ if n == 0 {
+ return Self::new();
+ }
if let Repr::Small { buf, len } = &self.0 {
let prev = usize::from(*len);
+ let new = prev.saturating_mul(n);
if new <= LIMIT {
let src = &buf[.. prev];
let mut buf = [0; LIMIT];
for i in 0 .. n {
buf[prev * i .. prev * (i + 1)].copy_from_slice(src);
}
- return Ok(Self(Repr::Small { buf, len: new as u8 }));
+ return Self(Repr::Small { buf, len: new as u8 });
}
}
- Ok(self.as_str().repeat(n).into())
- }
-}
-
-impl From<&Self> for EcoString {
- fn from(s: &Self) -> Self {
- s.clone()
- }
-}
-
-impl From<char> for EcoString {
- fn from(c: char) -> Self {
- let mut buf = [0; LIMIT];
- let len = c.encode_utf8(&mut buf).len();
- Self(Repr::Small { buf, len: len as u8 })
- }
-}
-
-impl From<&str> for EcoString {
- fn from(s: &str) -> Self {
- Self::from_str(s)
- }
-}
-
-impl From<String> for EcoString {
- fn from(s: String) -> Self {
- Self::from_str(s)
- }
-}
-
-impl From<&String> for EcoString {
- fn from(s: &String) -> Self {
- Self::from_str(s)
- }
-}
-
-impl From<EcoString> for String {
- fn from(s: EcoString) -> Self {
- match s.0 {
- Repr::Small { .. } => s.as_str().to_owned(),
- Repr::Large(rc) => match Rc::try_unwrap(rc) {
- Ok(string) => string,
- Err(rc) => (*rc).clone(),
- },
- }
- }
-}
-
-impl From<&EcoString> for String {
- fn from(s: &EcoString) -> Self {
- s.as_str().to_owned()
+ self.as_str().repeat(n).into()
}
}
@@ -236,18 +183,6 @@ impl Deref for EcoString {
}
}
-impl AsRef<str> for EcoString {
- fn as_ref(&self) -> &str {
- self
- }
-}
-
-impl Borrow<str> for EcoString {
- fn borrow(&self) -> &str {
- self
- }
-}
-
impl Default for EcoString {
fn default() -> Self {
Self::new()
@@ -286,12 +221,6 @@ impl PartialEq<&str> for EcoString {
}
}
-impl PartialEq<String> for EcoString {
- fn eq(&self, other: &String) -> bool {
- self.as_str().eq(other.as_str())
- }
-}
-
impl Ord for EcoString {
fn cmp(&self, other: &Self) -> Ordering {
self.as_str().cmp(other.as_str())
@@ -304,50 +233,77 @@ impl PartialOrd for EcoString {
}
}
-impl Add for EcoString {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self::Output {
- self + rhs.as_str()
+impl Hash for EcoString {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.as_str().hash(state);
}
}
-impl AddAssign for EcoString {
- fn add_assign(&mut self, rhs: EcoString) {
- self.push_str(&rhs);
+impl Write for EcoString {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ self.push_str(s);
+ Ok(())
+ }
+
+ fn write_char(&mut self, c: char) -> fmt::Result {
+ self.push(c);
+ Ok(())
}
}
-impl Add<&str> for EcoString {
- type Output = Self;
+impl AsRef<str> for EcoString {
+ fn as_ref(&self) -> &str {
+ self
+ }
+}
- fn add(mut self, rhs: &str) -> Self::Output {
- self.push_str(rhs);
+impl Borrow<str> for EcoString {
+ fn borrow(&self) -> &str {
self
}
}
-impl AddAssign<&str> for EcoString {
- fn add_assign(&mut self, rhs: &str) {
- self.push_str(rhs);
+impl From<&Self> for EcoString {
+ fn from(s: &Self) -> Self {
+ s.clone()
}
}
-impl Hash for EcoString {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.as_str().hash(state);
+impl From<char> for EcoString {
+ fn from(c: char) -> Self {
+ let mut buf = [0; LIMIT];
+ let len = c.encode_utf8(&mut buf).len();
+ Self(Repr::Small { buf, len: len as u8 })
}
}
-impl Write for EcoString {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- self.push_str(s);
- Ok(())
+impl From<&str> for EcoString {
+ fn from(s: &str) -> Self {
+ Self::from_str(s)
}
+}
- fn write_char(&mut self, c: char) -> fmt::Result {
- self.push(c);
- Ok(())
+impl From<String> for EcoString {
+ fn from(s: String) -> Self {
+ Self::from_str(s)
+ }
+}
+
+impl From<EcoString> for String {
+ fn from(s: EcoString) -> Self {
+ match s.0 {
+ Repr::Small { .. } => s.as_str().to_owned(),
+ Repr::Large(rc) => match Rc::try_unwrap(rc) {
+ Ok(string) => string,
+ Err(rc) => (*rc).clone(),
+ },
+ }
+ }
+}
+
+impl From<&EcoString> for String {
+ fn from(s: &EcoString) -> Self {
+ s.as_str().to_owned()
}
}
@@ -436,17 +392,13 @@ mod tests {
#[test]
fn test_str_repeat() {
// Test with empty string.
- assert_eq!(EcoString::new().repeat(0).unwrap(), "");
- assert_eq!(EcoString::new().repeat(100).unwrap(), "");
+ assert_eq!(EcoString::new().repeat(0), "");
+ assert_eq!(EcoString::new().repeat(100), "");
// Test non-spilling and spilling case.
let v = EcoString::from("abc");
- assert_eq!(v.repeat(0).unwrap(), "");
- assert_eq!(v.repeat(3).unwrap(), "abcabcabc");
- assert_eq!(v.repeat(5).unwrap(), "abcabcabcabcabc");
- assert_eq!(
- v.repeat(-1).unwrap_err(),
- "cannot repeat this string -1 times",
- );
+ assert_eq!(v.repeat(0), "");
+ assert_eq!(v.repeat(3), "abcabcabc");
+ assert_eq!(v.repeat(5), "abcabcabcabcabc");
}
}