1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use super::{Array, Value};
use crate::diag::StrResult;
use crate::util::EcoString;
/// Extra methods on strings.
pub trait StrExt {
/// Repeat a string a number of times.
fn repeat(&self, n: i64) -> StrResult<EcoString>;
/// Split this string at whitespace or a specific pattern.
fn split(&self, at: Option<EcoString>) -> Array;
}
impl StrExt for EcoString {
fn repeat(&self, n: i64) -> StrResult<EcoString> {
let n = usize::try_from(n)
.ok()
.and_then(|n| self.len().checked_mul(n).map(|_| n))
.ok_or_else(|| format!("cannot repeat this string {} times", n))?;
Ok(self.repeat(n))
}
fn split(&self, at: Option<EcoString>) -> Array {
if let Some(pat) = at {
self.as_str()
.split(pat.as_str())
.map(|s| Value::Str(s.into()))
.collect()
} else {
self.as_str()
.split_whitespace()
.map(|s| Value::Str(s.into()))
.collect()
}
}
}
/// A regular expression.
#[derive(Clone)]
pub struct Regex(regex::Regex);
impl Regex {
/// Create a new regex.
pub fn new(re: &str) -> StrResult<Self> {
regex::Regex::new(re).map(Self).map_err(|err| err.to_string())
}
/// Whether the regex matches the given `text`.
pub fn matches(&self, text: &str) -> bool {
self.0.is_match(text)
}
}
impl Deref for Regex {
type Target = regex::Regex;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Debug for Regex {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "regex({:?})", self.0.as_str())
}
}
impl PartialEq for Regex {
fn eq(&self, other: &Self) -> bool {
self.0.as_str() == other.0.as_str()
}
}
impl Hash for Regex {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.as_str().hash(state);
}
}
|