1use crate::{backend::HeapStr, KString, KStringCow, KStringRef, StackString};
2use core::fmt;
3use std::{borrow::Cow, string::String as StdString};
4
5#[macro_export]
19macro_rules! kformat {
20 ($($arg:tt)*) => {{
21 use core::fmt::Write;
22 let mut ks = $crate::KStringWriter::default();
23 write!(ks, $($arg)*).unwrap();
24 ks.into()
25 }};
26}
27
28#[derive(Clone)]
47pub enum KStringWriter {
48 Inline(StackString<{ KString::MAX_INLINE_LEN }>),
49 Owned(String),
50}
51
52impl KStringWriter {
53 pub fn new() -> Self {
54 Self::Inline(StackString::default())
55 }
56
57 pub fn reserve(&mut self, additional: usize) {
63 match self {
64 KStringWriter::Inline(inline) => {
65 let capacity = inline.len() + additional;
66 if capacity > KString::MAX_INLINE_LEN {
67 let mut owned = String::with_capacity(capacity);
69 owned.push_str(inline);
70 *self = KStringWriter::Owned(owned);
71 }
72 }
73 KStringWriter::Owned(owned) => {
74 owned.reserve(additional);
75 }
76 }
77 }
78
79 pub fn push(&mut self, ch: char) {
91 if let Self::Inline(inline) = self {
92 if inline.try_push_char(ch) {
93 return;
94 }
95 *self = Self::Owned(String::from(&*inline));
96 }
97 if let Self::Owned(owned) = self {
98 owned.push(ch);
99 } else {
100 unreachable!();
101 }
102 }
103
104 pub fn push_str(&mut self, s: &str) {
116 if let Self::Inline(inline) = self {
117 if inline.try_push(s) {
118 return;
119 }
120 *self = Self::Owned(String::from(&*inline));
121 }
122 if let Self::Owned(owned) = self {
123 owned.push_str(s);
124 } else {
125 unreachable!();
126 }
127 }
128}
129
130impl AsRef<str> for KStringWriter {
131 fn as_ref(&self) -> &str {
132 match self {
133 Self::Inline(inline) => inline.as_ref(),
134 Self::Owned(owned) => owned.as_ref(),
135 }
136 }
137}
138
139impl Default for KStringWriter {
140 fn default() -> Self {
141 Self::new()
142 }
143}
144
145impl<B: HeapStr> From<KStringWriter> for KString<B> {
146 fn from(writer: KStringWriter) -> Self {
147 match writer {
148 KStringWriter::Inline(inline) => inline.into(),
149 KStringWriter::Owned(owned) => owned.into(),
150 }
151 }
152}
153
154impl fmt::Write for KStringWriter {
155 fn write_str(&mut self, s: &str) -> fmt::Result {
156 self.push_str(s);
157 Ok(())
158 }
159}
160
161impl Extend<char> for KStringWriter {
162 fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
163 let iterator = iter.into_iter();
164 let (lower_bound, _) = iterator.size_hint();
165 self.reserve(lower_bound);
166 for c in iterator {
167 self.push(c);
168 }
169 }
170}
171
172impl<'a> Extend<&'a char> for KStringWriter {
173 fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
174 self.extend(iter.into_iter().cloned());
175 }
176}
177
178impl<'a> Extend<&'a str> for KStringWriter {
179 fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
180 for s in iter.into_iter() {
181 self.push_str(s);
182 }
183 }
184}
185
186impl Extend<Box<str>> for KStringWriter {
187 fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
188 for s in iter.into_iter() {
189 self.push_str(&s);
190 }
191 }
192}
193
194impl Extend<StdString> for KStringWriter {
195 fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
196 for s in iter.into_iter() {
197 self.push_str(&s);
198 }
199 }
200}
201
202impl<'a> Extend<Cow<'a, str>> for KStringWriter {
203 fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
204 for s in iter.into_iter() {
205 self.push_str(&s);
206 }
207 }
208}
209
210impl<'a, B: HeapStr> Extend<&'a KString<B>> for KStringWriter {
211 fn extend<I: IntoIterator<Item = &'a KString<B>>>(&mut self, iter: I) {
212 for s in iter.into_iter() {
213 self.push_str(s);
214 }
215 }
216}
217
218impl<B: HeapStr> Extend<KString<B>> for KStringWriter {
219 fn extend<I: IntoIterator<Item = KString<B>>>(&mut self, iter: I) {
220 for s in iter.into_iter() {
221 self.push_str(&s);
222 }
223 }
224}
225
226impl<'a, 's, B: HeapStr> Extend<&'a KStringCow<'s, B>> for KStringWriter {
227 fn extend<I: IntoIterator<Item = &'a KStringCow<'s, B>>>(&mut self, iter: I) {
228 for s in iter.into_iter() {
229 self.push_str(s);
230 }
231 }
232}
233
234impl<'s, B: HeapStr> Extend<KStringCow<'s, B>> for KStringWriter {
235 fn extend<I: IntoIterator<Item = KStringCow<'s, B>>>(&mut self, iter: I) {
236 for s in iter.into_iter() {
237 self.push_str(&s);
238 }
239 }
240}
241
242impl<'a, 's> Extend<&'a KStringRef<'s>> for KStringWriter {
243 fn extend<I: IntoIterator<Item = &'a KStringRef<'s>>>(&mut self, iter: I) {
244 for s in iter.into_iter() {
245 self.push_str(s);
246 }
247 }
248}
249
250impl<'s> Extend<KStringRef<'s>> for KStringWriter {
251 fn extend<I: IntoIterator<Item = KStringRef<'s>>>(&mut self, iter: I) {
252 for s in iter.into_iter() {
253 self.push_str(&s);
254 }
255 }
256}
257
258impl<B: HeapStr> FromIterator<char> for KString<B> {
259 fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
260 let mut writer = KStringWriter::new();
261 writer.extend(iter);
262 writer.into()
263 }
264}
265
266impl<'a, B: HeapStr> FromIterator<&'a char> for KString<B> {
267 fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> Self {
268 let mut writer = KStringWriter::new();
269 writer.extend(iter);
270 writer.into()
271 }
272}
273
274impl<'a, B: HeapStr> FromIterator<&'a str> for KString<B> {
275 fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {
276 let mut writer = KStringWriter::new();
277 writer.extend(iter);
278 writer.into()
279 }
280}
281
282impl<B: HeapStr> FromIterator<Box<str>> for KString<B> {
283 fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> KString<B> {
284 let mut writer = KStringWriter::new();
285 writer.extend(iter);
286 writer.into()
287 }
288}
289
290impl<'a, B: HeapStr> FromIterator<Cow<'a, str>> for KString<B> {
291 fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> KString<B> {
292 let mut iterator = iter.into_iter();
293
294 match iterator.next() {
295 None => KString::new(),
296 Some(cow) => {
297 let mut writer = cow.into_owned();
298 writer.extend(iterator);
299 writer.into()
300 }
301 }
302 }
303}
304
305impl<'a, D: HeapStr, B: HeapStr> FromIterator<&'a KString<D>> for KString<B> {
306 fn from_iter<I: IntoIterator<Item = &'a KString<D>>>(iter: I) -> KString<B> {
307 let mut writer = KStringWriter::new();
308 writer.extend(iter);
309 writer.into()
310 }
311}
312
313impl<D: HeapStr, B: HeapStr> FromIterator<KString<D>> for KString<B> {
314 fn from_iter<I: IntoIterator<Item = KString<D>>>(iter: I) -> KString<B> {
315 let mut writer = KStringWriter::new();
316 writer.extend(iter);
317 writer.into()
318 }
319}
320
321impl<'a, 's, B: HeapStr, D: HeapStr> FromIterator<&'a KStringCow<'s, D>> for KString<B> {
322 fn from_iter<I: IntoIterator<Item = &'a KStringCow<'s, D>>>(iter: I) -> KString<B> {
323 let mut writer = KStringWriter::new();
324 writer.extend(iter);
325 writer.into()
326 }
327}
328
329impl<'s, B: HeapStr, D: HeapStr> FromIterator<KStringCow<'s, D>> for KString<B> {
330 fn from_iter<I: IntoIterator<Item = KStringCow<'s, D>>>(iter: I) -> KString<B> {
331 let mut writer = KStringWriter::new();
332 writer.extend(iter);
333 writer.into()
334 }
335}
336
337impl<'a, 's, B: HeapStr> FromIterator<&'a KStringRef<'s>> for KString<B> {
338 fn from_iter<I: IntoIterator<Item = &'a KStringRef<'s>>>(iter: I) -> KString<B> {
339 let mut writer = KStringWriter::new();
340 writer.extend(iter);
341 writer.into()
342 }
343}
344
345impl<'s, B: HeapStr> FromIterator<KStringRef<'s>> for KString<B> {
346 fn from_iter<I: IntoIterator<Item = KStringRef<'s>>>(iter: I) -> KString<B> {
347 let mut writer = KStringWriter::new();
348 writer.extend(iter);
349 writer.into()
350 }
351}
352
353#[cfg(test)]
354mod tests {
355 use super::*;
356
357 #[test]
358 fn test_kstringwriter_new() {
359 let writer = KStringWriter::new();
360 assert!(matches!(writer, KStringWriter::Inline(_)));
361 }
362
363 #[test]
364 fn test_kstringwriter_push_char_inline() {
365 let mut writer = KStringWriter::new();
366 writer.push('a');
367 assert_eq!(writer.as_ref(), "a");
368 }
369
370 #[test]
371 fn test_kstringwriter_push_str_inline() {
372 let mut writer = KStringWriter::new();
373 writer.push_str("abc");
374 assert_eq!(writer.as_ref(), "abc");
375 }
376
377 #[test]
378 fn test_kstringwriter_push_char_to_owned() {
379 let mut writer = KStringWriter::new();
380 for _ in 0..=KString::MAX_INLINE_LEN {
381 writer.push('a');
382 }
383 assert!(matches!(writer, KStringWriter::Owned(_)));
384 assert_eq!(writer.as_ref(), "a".repeat(KString::MAX_INLINE_LEN + 1));
385 }
386
387 #[test]
388 fn test_kstringwriter_push_str_to_owned() {
389 let mut writer = KStringWriter::new();
390 for _ in 0..=KString::MAX_INLINE_LEN / 3 {
391 writer.push_str("abc");
392 }
393 assert!(matches!(writer, KStringWriter::Owned(_)));
394 assert_eq!(
395 writer.as_ref(),
396 "abc".repeat(KString::MAX_INLINE_LEN / 3 + 1)
397 );
398 }
399
400 #[test]
401 fn test_kstringwriter_reserve_inline() {
402 let mut writer = KStringWriter::new();
403 writer.reserve(KString::MAX_INLINE_LEN);
404 assert!(matches!(writer, KStringWriter::Inline(_)));
405
406 let mut writer = KStringWriter::new();
407 writer.push('a');
408 writer.reserve(KString::MAX_INLINE_LEN - 1);
409 assert!(matches!(writer, KStringWriter::Inline(_)));
410 }
411
412 #[test]
413 fn test_kstringwriter_reserve_to_owned() {
414 let mut writer = KStringWriter::new();
415 writer.reserve(KString::MAX_INLINE_LEN + 1);
416 assert!(matches!(writer, KStringWriter::Owned(_)));
417
418 let mut writer = KStringWriter::new();
419 writer.push('a');
420 writer.reserve(KString::MAX_INLINE_LEN);
421 assert!(matches!(writer, KStringWriter::Owned(_)));
422 }
423
424 #[test]
425 fn test_kstringwriter_from_writer_inline() {
426 let mut writer = KStringWriter::new();
427 writer.push_str("abc");
428 let kstring: KString = writer.into();
429 assert_eq!(&kstring, "abc");
430 }
431
432 #[test]
433 fn test_kstringwriter_from_writer_owned() {
434 let mut writer = KStringWriter::new();
435 for _ in 0..=KString::MAX_INLINE_LEN / 3 {
436 writer.push_str("abc");
437 }
438 let kstring: KString = writer.into();
439 assert_eq!(&kstring, &"abc".repeat(KString::MAX_INLINE_LEN / 3 + 1));
440 }
441
442 #[test]
443 fn test_kstringwriter_extend_char() {
444 let mut writer = KStringWriter::new();
445 writer.extend("hello".chars());
446 assert_eq!(writer.as_ref(), "hello");
447 }
448
449 #[test]
450 fn test_kstringwriter_extend_str() {
451 let mut writer = KStringWriter::new();
452 writer.extend(["he", "ll", "o"]);
453 assert_eq!(writer.as_ref(), "hello");
454 }
455}