sage_runtime/stdlib/
string.rs1#[must_use]
6pub fn str_index_of(haystack: &str, needle: &str) -> Option<i64> {
7 haystack.find(needle).map(|byte_pos| {
8 haystack[..byte_pos].chars().count() as i64
10 })
11}
12
13#[must_use]
16pub fn str_slice(s: &str, start: i64, end: i64) -> String {
17 let start = start.max(0) as usize;
18 let end = end.max(0) as usize;
19 s.chars()
20 .skip(start)
21 .take(end.saturating_sub(start))
22 .collect()
23}
24
25#[must_use]
27pub fn str_pad_start(s: &str, target_len: i64, pad: &str) -> String {
28 let target_len = target_len.max(0) as usize;
29 let current_len = s.chars().count();
30 if current_len >= target_len || pad.is_empty() {
31 return s.to_string();
32 }
33 let needed = target_len - current_len;
34 let pad_chars: Vec<char> = pad.chars().collect();
35 let mut result = String::new();
36 for i in 0..needed {
37 result.push(pad_chars[i % pad_chars.len()]);
38 }
39 result.push_str(s);
40 result
41}
42
43#[must_use]
45pub fn str_pad_end(s: &str, target_len: i64, pad: &str) -> String {
46 let target_len = target_len.max(0) as usize;
47 let current_len = s.chars().count();
48 if current_len >= target_len || pad.is_empty() {
49 return s.to_string();
50 }
51 let needed = target_len - current_len;
52 let pad_chars: Vec<char> = pad.chars().collect();
53 let mut result = s.to_string();
54 for i in 0..needed {
55 result.push(pad_chars[i % pad_chars.len()]);
56 }
57 result
58}
59
60#[must_use]
63pub fn list_slice<T: Clone>(list: Vec<T>, start: i64, end: i64) -> Vec<T> {
64 let len = list.len();
65 let start = start.max(0) as usize;
66 let end = end.max(0) as usize;
67 let start = start.min(len);
68 let end = end.min(len);
69 if start >= end {
70 return Vec::new();
71 }
72 list[start..end].to_vec()
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn test_list_slice() {
81 assert_eq!(list_slice(vec![1, 2, 3, 4, 5], 1, 4), vec![2, 3, 4]);
82 assert_eq!(list_slice(vec![1, 2, 3], 0, 10), vec![1, 2, 3]);
83 assert_eq!(list_slice(vec![1, 2, 3], -5, 2), vec![1, 2]);
84 assert_eq!(list_slice(vec![1, 2, 3], 5, 10), Vec::<i64>::new());
85 }
86
87 #[test]
88 fn test_str_index_of() {
89 assert_eq!(str_index_of("hello world", "world"), Some(6));
90 assert_eq!(str_index_of("hello world", "foo"), None);
91 assert_eq!(str_index_of("hello", ""), Some(0));
92 assert_eq!(str_index_of("héllo wörld", "wörld"), Some(6));
94 }
95
96 #[test]
97 fn test_str_slice() {
98 assert_eq!(str_slice("hello", 1, 4), "ell");
99 assert_eq!(str_slice("hello", 0, 5), "hello");
100 assert_eq!(str_slice("hello", 3, 100), "lo");
101 assert_eq!(str_slice("hello", -5, 3), "hel");
102 assert_eq!(str_slice("héllo", 0, 3), "hél");
104 }
105
106 #[test]
107 fn test_str_pad_start() {
108 assert_eq!(str_pad_start("5", 3, "0"), "005");
109 assert_eq!(str_pad_start("hello", 3, "x"), "hello");
110 assert_eq!(str_pad_start("a", 5, "xy"), "xyxya");
111 }
112
113 #[test]
114 fn test_str_pad_end() {
115 assert_eq!(str_pad_end("5", 3, "0"), "500");
116 assert_eq!(str_pad_end("hello", 3, "x"), "hello");
117 assert_eq!(str_pad_end("a", 5, "xy"), "axyxy");
118 }
119}