1use ferray_core::dimension::Dimension;
25use ferray_core::error::FerrayResult;
26
27use crate::string_array::StringArray;
28
29pub fn center<D: Dimension>(
36 a: &StringArray<D>,
37 width: usize,
38 fillchar: char,
39) -> FerrayResult<StringArray<D>> {
40 a.map(|s| {
41 let char_count = s.chars().count();
42 if char_count >= width {
43 return s.to_string();
44 }
45 let total_pad = width - char_count;
46 let left_pad = total_pad / 2 + (total_pad & width & 1);
51 let right_pad = total_pad - left_pad;
52 let mut result = String::with_capacity(s.len() + total_pad);
53 for _ in 0..left_pad {
54 result.push(fillchar);
55 }
56 result.push_str(s);
57 for _ in 0..right_pad {
58 result.push(fillchar);
59 }
60 result
61 })
62}
63
64pub fn ljust<D: Dimension>(a: &StringArray<D>, width: usize) -> FerrayResult<StringArray<D>> {
71 ljust_with(a, width, ' ')
72}
73
74pub fn ljust_with<D: Dimension>(
81 a: &StringArray<D>,
82 width: usize,
83 fillchar: char,
84) -> FerrayResult<StringArray<D>> {
85 a.map(|s| {
86 let char_count = s.chars().count();
87 if char_count >= width {
88 return s.to_string();
89 }
90 let pad = width - char_count;
91 let mut result = String::with_capacity(s.len() + pad * fillchar.len_utf8());
92 result.push_str(s);
93 for _ in 0..pad {
94 result.push(fillchar);
95 }
96 result
97 })
98}
99
100pub fn rjust<D: Dimension>(a: &StringArray<D>, width: usize) -> FerrayResult<StringArray<D>> {
107 rjust_with(a, width, ' ')
108}
109
110pub fn rjust_with<D: Dimension>(
117 a: &StringArray<D>,
118 width: usize,
119 fillchar: char,
120) -> FerrayResult<StringArray<D>> {
121 a.map(|s| {
122 let char_count = s.chars().count();
123 if char_count >= width {
124 return s.to_string();
125 }
126 let pad = width - char_count;
127 let mut result = String::with_capacity(s.len() + pad * fillchar.len_utf8());
128 for _ in 0..pad {
129 result.push(fillchar);
130 }
131 result.push_str(s);
132 result
133 })
134}
135
136pub fn zfill<D: Dimension>(a: &StringArray<D>, width: usize) -> FerrayResult<StringArray<D>> {
145 a.map(|s| {
146 let char_count = s.chars().count();
147 if char_count >= width {
148 return s.to_string();
149 }
150 let pad = width - char_count;
151 let (sign, rest) = if s.starts_with('+') || s.starts_with('-') {
152 (&s[..1], &s[1..])
153 } else {
154 ("", s)
155 };
156 let mut result = String::with_capacity(s.len() + pad);
157 result.push_str(sign);
158 for _ in 0..pad {
159 result.push('0');
160 }
161 result.push_str(rest);
162 result
163 })
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 use crate::string_array::array;
170
171 #[test]
172 fn test_center() {
173 let a = array(&["hi", "x"]).unwrap();
174 let b = center(&a, 6, '*').unwrap();
175 assert_eq!(b.as_slice(), &["**hi**", "**x***"]);
176 }
177
178 #[test]
179 fn test_center_no_pad_needed() {
180 let a = array(&["hello"]).unwrap();
181 let b = center(&a, 3, ' ').unwrap();
182 assert_eq!(b.as_slice(), &["hello"]);
183 }
184
185 #[test]
186 fn test_ljust() {
187 let a = array(&["hi", "hello"]).unwrap();
188 let b = ljust(&a, 6).unwrap();
189 assert_eq!(b.as_slice(), &["hi ", "hello "]);
190 }
191
192 #[test]
193 fn test_ljust_no_pad_needed() {
194 let a = array(&["hello"]).unwrap();
195 let b = ljust(&a, 3).unwrap();
196 assert_eq!(b.as_slice(), &["hello"]);
197 }
198
199 #[test]
200 fn test_rjust() {
201 let a = array(&["hi", "hello"]).unwrap();
202 let b = rjust(&a, 6).unwrap();
203 assert_eq!(b.as_slice(), &[" hi", " hello"]);
204 }
205
206 #[test]
207 fn test_ljust_with_fillchar() {
208 let a = array(&["hi"]).unwrap();
209 let b = ljust_with(&a, 6, '-').unwrap();
210 assert_eq!(b.as_slice(), &["hi----"]);
211 }
212
213 #[test]
214 fn test_rjust_with_fillchar() {
215 let a = array(&["hi"]).unwrap();
216 let b = rjust_with(&a, 6, '.').unwrap();
217 assert_eq!(b.as_slice(), &["....hi"]);
218 }
219
220 #[test]
221 fn test_ljust_with_unicode_fillchar() {
222 let a = array(&["ab"]).unwrap();
223 let b = ljust_with(&a, 5, '★').unwrap();
224 assert_eq!(b.as_slice(), &["ab★★★"]);
225 }
226
227 #[test]
228 fn test_zfill() {
229 let a = array(&["42", "-17", "+5", "abc"]).unwrap();
230 let b = zfill(&a, 5).unwrap();
231 assert_eq!(b.as_slice(), &["00042", "-0017", "+0005", "00abc"]);
232 }
233
234 #[test]
235 fn test_zfill_no_pad_needed() {
236 let a = array(&["12345"]).unwrap();
237 let b = zfill(&a, 3).unwrap();
238 assert_eq!(b.as_slice(), &["12345"]);
239 }
240}