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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use crate::data::{
self,
int::{INT_MAX, INT_MIN},
Data, MersDataWInfo, Type,
};
use super::{
gen::{function::func, AnyOrNone, IntR, IterToList, OneOf, OneOrNone},
util, Config,
};
impl Config {
/// `trim: fn` removes leading and trailing whitespace from a string
/// `substring: fn` extracts part of a string. usage: (str, start).substring or (str, start, end).substring. start and end may be negative, in which case they become str.len - n: (str, 0, -1) shortens the string by 1.
/// `index_of: fn` finds the index of a pattern in a string
/// `index_of_rev: fn` finds the last index of a pattern in a string
/// `starts_with: fn` checks if the string starts with the pattern
/// `ends_with: fn` checks if the string ends with the pattern
/// `str_split_once: fn` splits the string at the given pattern, removing that pattern from the string.
/// `str_split_once_rev: fn` like split_str_once, but splits at the last found instance of the pattern instead of the first.
/// `str_split: fn` splits the string at the given pattern, removing that pattern from the string.
/// `to_string: fn` turns any argument into a (more or less useful) string representation
/// `concat: fn` concatenates all arguments given to it. arg must be an enumerable
pub fn with_string(self) -> Self {
self.add_var("trim", func(|v: &str, _| Ok(v.trim().to_owned())))
.add_var(
"index_of",
func(|(v, p): (&str, &str), _| {
Ok(OneOrNone(v.find(p).map(|v| IntR::<0, INT_MAX>(v as isize))))
}),
)
.add_var(
"index_of_rev",
func(|(v, p): (&str, &str), _| {
Ok(OneOrNone(
v.rfind(p).map(|v| IntR::<0, INT_MAX>(v as isize)),
))
}),
)
.add_var(
"starts_with",
func(|(v, p): (&str, &str), _| Ok(v.starts_with(p))),
)
.add_var(
"ends_with",
func(|(v, p): (&str, &str), _| Ok(v.ends_with(p))),
)
.add_var(
"str_split_once",
func(|(v, p): (&str, &str), _| {
Ok(AnyOrNone(
v.split_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())),
))
}),
)
.add_var(
"str_split_once_rev",
func(|(v, p): (&str, &str), _| {
Ok(AnyOrNone(
v.rsplit_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())),
))
}),
)
.add_var(
"str_split",
func(|(v, p): (&str, &str), _| Ok(IterToList(v.split(p).map(|v| v.to_owned())))),
)
.add_var(
"concat",
util::to_mers_func(
|a, i| {
if a.iterable().is_some() {
Ok(Type::new(data::string::StringT))
} else {
Err(
format!("concat called on non-iterable type {}", a.with_info(i))
.into(),
)
}
},
|a, i| {
Ok(Data::new(data::string::String(
a.get()
.iterable(&i.global)
.unwrap()
.map(|v| v.map(|v| v.get().with_info(i).to_string()))
.collect::<Result<_, _>>()?,
)))
},
),
)
.add_var(
"to_string",
util::to_mers_func(
|_a, _| Ok(Type::new(data::string::StringT)),
|a, i| {
Ok(Data::new(data::string::String(
a.get().with_info(i).to_string(),
)))
},
),
)
.add_var(
"substring",
func(
|v: OneOf<
(&str, IntR<INT_MIN, INT_MAX>),
(&str, IntR<INT_MIN, INT_MAX>, IntR<INT_MIN, INT_MAX>),
>,
_| {
let (s, start, end) = match v {
OneOf::A((t, s)) => (t, s.0, None),
OneOf::B((t, s, e)) => (t, s.0, Some(e.0)),
};
let start = if start < 0 {
s.len().saturating_sub(start.abs() as usize)
} else {
start as usize
};
let end = end
.map(|i| {
if i < 0 {
s.len().saturating_sub(i.abs() as usize)
} else {
i as usize
}
})
.unwrap_or(usize::MAX);
let end = end.min(s.len());
if end < start {
return Ok(String::new());
}
Ok(s[start..end].to_owned())
},
),
)
}
}