1use alloc::borrow::Cow;
2use alloc::str;
3use alloc::string::String;
4use core::cell::Cell;
5use core::convert::Infallible;
6use core::fmt::{self, Write};
7use core::ops::Deref;
8use core::pin::Pin;
9
10use super::MAX_LEN;
11use super::escape::HtmlSafeOutput;
12use crate::{FastWritable, Result};
13
14macro_rules! try_to_str {
21 ($src:expr => $buffer:ident) => {
22 match format_args!("{}", $src) {
23 args => {
24 if let Some(s) = args.as_str() {
25 s
26 } else {
27 $buffer = String::new();
28 $buffer.write_fmt(args)?;
29 &$buffer
30 }
31 }
32 }
33 };
34}
35
36pub fn fmt() {}
69
70pub fn format() {}
102
103#[inline]
127pub fn linebreaks<S: fmt::Display>(source: S) -> Result<HtmlSafeOutput<Linebreaks<S>>, Infallible> {
128 Ok(HtmlSafeOutput(Linebreaks(source)))
129}
130
131pub struct Linebreaks<S>(S);
132
133impl<S: fmt::Display> fmt::Display for Linebreaks<S> {
134 #[inline]
135 fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
136 let mut buffer;
137 flush_linebreaks(dest, try_to_str!(self.0 => buffer))
138 }
139}
140
141impl<S: FastWritable> FastWritable for Linebreaks<S> {
142 #[inline]
143 fn write_into<W: fmt::Write + ?Sized>(
144 &self,
145 dest: &mut W,
146 values: &dyn crate::Values,
147 ) -> crate::Result<()> {
148 let mut buffer = String::new();
149 self.0.write_into(&mut buffer, values)?;
150 Ok(flush_linebreaks(dest, &buffer)?)
151 }
152}
153
154fn flush_linebreaks(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
155 let linebroken = s.replace("\n\n", "</p><p>").replace('\n', "<br/>");
156 write!(dest, "<p>{linebroken}</p>")
157}
158
159#[inline]
180pub fn linebreaksbr<S: fmt::Display>(
181 source: S,
182) -> Result<HtmlSafeOutput<Linebreaksbr<S>>, Infallible> {
183 Ok(HtmlSafeOutput(Linebreaksbr(source)))
184}
185
186pub struct Linebreaksbr<S>(S);
187
188impl<S: fmt::Display> fmt::Display for Linebreaksbr<S> {
189 #[inline]
190 fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
191 let mut buffer;
192 flush_linebreaksbr(dest, try_to_str!(self.0 => buffer))
193 }
194}
195
196impl<S: FastWritable> FastWritable for Linebreaksbr<S> {
197 #[inline]
198 fn write_into<W: fmt::Write + ?Sized>(
199 &self,
200 dest: &mut W,
201 values: &dyn crate::Values,
202 ) -> crate::Result<()> {
203 let mut buffer = String::new();
204 self.0.write_into(&mut buffer, values)?;
205 Ok(flush_linebreaksbr(dest, &buffer)?)
206 }
207}
208
209fn flush_linebreaksbr(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
210 dest.write_str(&s.replace('\n', "<br/>"))
211}
212
213#[inline]
238pub fn paragraphbreaks<S: fmt::Display>(
239 source: S,
240) -> Result<HtmlSafeOutput<Paragraphbreaks<S>>, Infallible> {
241 Ok(HtmlSafeOutput(Paragraphbreaks(source)))
242}
243
244pub struct Paragraphbreaks<S>(S);
245
246impl<S: fmt::Display> fmt::Display for Paragraphbreaks<S> {
247 #[inline]
248 fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
249 let mut buffer;
250 flush_paragraphbreaks(dest, try_to_str!(self.0 => buffer))
251 }
252}
253
254impl<S: FastWritable> FastWritable for Paragraphbreaks<S> {
255 #[inline]
256 fn write_into<W: fmt::Write + ?Sized>(
257 &self,
258 dest: &mut W,
259 values: &dyn crate::Values,
260 ) -> crate::Result<()> {
261 let mut buffer = String::new();
262 self.0.write_into(&mut buffer, values)?;
263 Ok(flush_paragraphbreaks(dest, &buffer)?)
264 }
265}
266
267fn flush_paragraphbreaks(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
268 let linebroken = s.replace("\n\n", "</p><p>").replace("<p></p>", "");
269 write!(dest, "<p>{linebroken}</p>")
270}
271
272#[inline]
298pub fn lower<S: fmt::Display>(source: S) -> Result<Lower<S>, Infallible> {
299 Ok(Lower(source))
300}
301
302pub struct Lower<S>(S);
303
304impl<S: fmt::Display> fmt::Display for Lower<S> {
305 #[inline]
306 fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
307 let mut buffer;
308 flush_lower(dest, try_to_str!(self.0 => buffer))
309 }
310}
311
312impl<S: FastWritable> FastWritable for Lower<S> {
313 #[inline]
314 fn write_into<W: fmt::Write + ?Sized>(
315 &self,
316 dest: &mut W,
317 values: &dyn crate::Values,
318 ) -> crate::Result<()> {
319 let mut buffer = String::new();
320 self.0.write_into(&mut buffer, values)?;
321 Ok(flush_lower(dest, &buffer)?)
322 }
323}
324
325fn flush_lower(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
326 dest.write_str(&s.to_lowercase())
327}
328
329#[inline]
355pub fn lowercase<S: fmt::Display>(source: S) -> Result<Lower<S>, Infallible> {
356 lower(source)
357}
358
359#[inline]
385pub fn upper<S: fmt::Display>(source: S) -> Result<Upper<S>, Infallible> {
386 Ok(Upper(source))
387}
388
389pub struct Upper<S>(S);
390
391impl<S: fmt::Display> fmt::Display for Upper<S> {
392 #[inline]
393 fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
394 let mut buffer;
395 flush_upper(dest, try_to_str!(self.0 => buffer))
396 }
397}
398
399impl<S: FastWritable> FastWritable for Upper<S> {
400 #[inline]
401 fn write_into<W: fmt::Write + ?Sized>(
402 &self,
403 dest: &mut W,
404 values: &dyn crate::Values,
405 ) -> crate::Result<()> {
406 let mut buffer = String::new();
407 self.0.write_into(&mut buffer, values)?;
408 Ok(flush_upper(dest, &buffer)?)
409 }
410}
411
412fn flush_upper(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
413 dest.write_str(&s.to_uppercase())
414}
415
416#[inline]
442pub fn uppercase<S: fmt::Display>(source: S) -> Result<Upper<S>, Infallible> {
443 upper(source)
444}
445
446#[inline]
467pub fn trim<S: fmt::Display>(source: S) -> Result<Trim<S>, Infallible> {
468 Ok(Trim(source))
469}
470
471pub struct Trim<S>(S);
472
473impl<S: fmt::Display> fmt::Display for Trim<S> {
474 #[inline]
475 fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
476 let mut collector = TrimCollector(String::new());
477 write!(collector, "{}", self.0)?;
478 flush_trim(dest, collector)
479 }
480}
481
482impl<S: FastWritable> FastWritable for Trim<S> {
483 #[inline]
484 fn write_into<W: fmt::Write + ?Sized>(
485 &self,
486 dest: &mut W,
487 values: &dyn crate::Values,
488 ) -> crate::Result<()> {
489 let mut collector = TrimCollector(String::new());
490 self.0.write_into(&mut collector, values)?;
491 Ok(flush_trim(dest, collector)?)
492 }
493}
494
495struct TrimCollector(String);
496
497impl fmt::Write for TrimCollector {
498 fn write_str(&mut self, s: &str) -> fmt::Result {
499 match self.0.is_empty() {
500 true => self.0.write_str(s.trim_start()),
501 false => self.0.write_str(s),
502 }
503 }
504}
505
506fn flush_trim(dest: &mut (impl fmt::Write + ?Sized), collector: TrimCollector) -> fmt::Result {
507 dest.write_str(collector.0.trim_end())
508}
509
510#[inline]
558pub fn indent<S, I: AsIndent>(
559 source: S,
560 indent: I,
561 first: bool,
562 blank: bool,
563) -> Result<Indent<S, I>, Infallible> {
564 Ok(Indent {
565 source,
566 indent,
567 first,
568 blank,
569 })
570}
571
572pub struct Indent<S, I> {
573 source: S,
574 indent: I,
575 first: bool,
576 blank: bool,
577}
578
579impl<S: fmt::Display, I: AsIndent> fmt::Display for Indent<S, I> {
580 fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
581 let indent = self.indent.as_indent();
582 if indent.len() >= MAX_LEN || indent.is_empty() {
583 write!(dest, "{}", self.source)
584 } else {
585 let mut buffer;
586 let buffer = try_to_str!(self.source => buffer);
587 flush_indent(dest, indent, buffer, self.first, self.blank)
588 }
589 }
590}
591
592impl<S: FastWritable, I: AsIndent> FastWritable for Indent<S, I> {
593 fn write_into<W: fmt::Write + ?Sized>(
594 &self,
595 dest: &mut W,
596 values: &dyn crate::Values,
597 ) -> crate::Result<()> {
598 let indent = self.indent.as_indent();
599 if indent.len() >= MAX_LEN || indent.is_empty() {
600 self.source.write_into(dest, values)
601 } else {
602 let mut buffer = String::new();
603 self.source.write_into(&mut buffer, values)?;
604 Ok(flush_indent(dest, indent, &buffer, self.first, self.blank)?)
605 }
606 }
607}
608
609fn flush_indent(
610 dest: &mut (impl fmt::Write + ?Sized),
611 indent: &str,
612 s: &str,
613 first: bool,
614 blank: bool,
615) -> fmt::Result {
616 if s.len() >= MAX_LEN {
617 return dest.write_str(s);
618 }
619
620 for (idx, line) in s.split_inclusive('\n').enumerate() {
621 if (first || idx > 0) && (blank || !matches!(line, "\n" | "\r\n")) {
622 dest.write_str(indent)?;
623 }
624 dest.write_str(line)?;
625 }
626 Ok(())
627}
628
629#[inline]
655pub fn capitalize<S: fmt::Display>(source: S) -> Result<Capitalize<S>, Infallible> {
656 Ok(Capitalize(source))
657}
658
659pub struct Capitalize<S>(S);
660
661impl<S: fmt::Display> fmt::Display for Capitalize<S> {
662 #[inline]
663 fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
664 let mut buffer;
665 flush_capitalize(dest, try_to_str!(self.0 => buffer))
666 }
667}
668
669impl<S: FastWritable> FastWritable for Capitalize<S> {
670 #[inline]
671 fn write_into<W: fmt::Write + ?Sized>(
672 &self,
673 dest: &mut W,
674 values: &dyn crate::Values,
675 ) -> crate::Result<()> {
676 let mut buffer = String::new();
677 self.0.write_into(&mut buffer, values)?;
678 Ok(flush_capitalize(dest, &buffer)?)
679 }
680}
681
682fn flush_capitalize(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
683 let mut chars = s.chars();
684 if let Some(c) = chars.next() {
685 write!(
686 dest,
687 "{}{}",
688 c.to_uppercase(),
689 chars.as_str().to_lowercase()
690 )
691 } else {
692 Ok(())
693 }
694}
695
696#[inline]
717pub fn wordcount<S>(source: S) -> Wordcount<S> {
718 Wordcount(Cell::new(Some(WordcountInner {
719 source,
720 buffer: String::new(),
721 })))
722}
723
724pub struct Wordcount<S>(Cell<Option<WordcountInner<S>>>);
725
726struct WordcountInner<S> {
727 source: S,
728 buffer: String,
729}
730
731impl<S: fmt::Display> fmt::Display for Wordcount<S> {
732 #[inline]
733 fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
734 if let Some(mut inner) = self.0.take() {
735 write!(inner.buffer, "{}", inner.source)?;
736 self.0.set(Some(inner));
737 }
738 Ok(())
739 }
740}
741
742impl<S: FastWritable> FastWritable for Wordcount<S> {
743 #[inline]
744 fn write_into<W: fmt::Write + ?Sized>(
745 &self,
746 _: &mut W,
747 values: &dyn crate::Values,
748 ) -> crate::Result<()> {
749 if let Some(mut inner) = self.0.take() {
750 inner.source.write_into(&mut inner.buffer, values)?;
751 self.0.set(Some(inner));
752 }
753 Ok(())
754 }
755}
756
757impl<S> Wordcount<S> {
758 pub fn into_count(self) -> usize {
759 if let Some(inner) = self.0.into_inner() {
760 inner.buffer.split_whitespace().count()
761 } else {
762 0
763 }
764 }
765}
766
767#[inline]
789pub fn title<S: fmt::Display>(source: S) -> Result<Title<S>, Infallible> {
790 Ok(Title(source))
791}
792
793pub struct Title<S>(S);
794
795impl<S: fmt::Display> fmt::Display for Title<S> {
796 #[inline]
797 fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
798 let mut buffer;
799 flush_title(dest, try_to_str!(self.0 => buffer))
800 }
801}
802
803impl<S: FastWritable> FastWritable for Title<S> {
804 #[inline]
805 fn write_into<W: fmt::Write + ?Sized>(
806 &self,
807 dest: &mut W,
808 values: &dyn crate::Values,
809 ) -> crate::Result<()> {
810 let mut buffer = String::new();
811 self.0.write_into(&mut buffer, values)?;
812 Ok(flush_title(dest, &buffer)?)
813 }
814}
815
816fn flush_title(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
817 for word in s.split_inclusive(char::is_whitespace) {
818 flush_capitalize(dest, word)?;
819 }
820 Ok(())
821}
822
823#[inline]
844pub fn titlecase<S: fmt::Display>(source: S) -> Result<Title<S>, Infallible> {
845 title(source)
846}
847
848pub trait AsIndent {
857 fn as_indent(&self) -> &str;
859}
860
861impl AsIndent for str {
862 #[inline]
863 fn as_indent(&self) -> &str {
864 self
865 }
866}
867
868#[cfg(feature = "alloc")]
869impl AsIndent for alloc::string::String {
870 #[inline]
871 fn as_indent(&self) -> &str {
872 self
873 }
874}
875
876impl AsIndent for usize {
877 #[inline]
878 fn as_indent(&self) -> &str {
879 spaces(*self)
880 }
881}
882
883impl AsIndent for core::num::Wrapping<usize> {
884 #[inline]
885 fn as_indent(&self) -> &str {
886 spaces(self.0)
887 }
888}
889
890impl AsIndent for core::num::NonZeroUsize {
891 #[inline]
892 fn as_indent(&self) -> &str {
893 spaces(self.get())
894 }
895}
896
897fn spaces(width: usize) -> &'static str {
898 const MAX_SPACES: usize = 16;
899 const SPACES: &str = match str::from_utf8(&[b' '; MAX_SPACES]) {
900 Ok(spaces) => spaces,
901 Err(_) => panic!(),
902 };
903
904 &SPACES[..width.min(SPACES.len())]
905}
906
907#[cfg(feature = "alloc")]
908impl<T: AsIndent + alloc::borrow::ToOwned + ?Sized> AsIndent for Cow<'_, T> {
909 #[inline]
910 fn as_indent(&self) -> &str {
911 T::as_indent(self)
912 }
913}
914
915crate::impl_for_ref! {
916 impl AsIndent for T {
917 #[inline]
918 fn as_indent(&self) -> &str {
919 <T>::as_indent(self)
920 }
921 }
922}
923
924impl<T> AsIndent for Pin<T>
925where
926 T: Deref,
927 <T as Deref>::Target: AsIndent,
928{
929 #[inline]
930 fn as_indent(&self) -> &str {
931 self.as_ref().get_ref().as_indent()
932 }
933}
934
935#[cfg(test)]
936mod tests {
937 use alloc::string::ToString;
938 use std::borrow::ToOwned;
939
940 use super::*;
941 use crate::NO_VALUES;
942
943 #[test]
944 fn test_linebreaks() {
945 assert_eq!(
946 linebreaks("Foo\nBar Baz").unwrap().to_string(),
947 "<p>Foo<br/>Bar Baz</p>"
948 );
949 assert_eq!(
950 linebreaks("Foo\nBar\n\nBaz").unwrap().to_string(),
951 "<p>Foo<br/>Bar</p><p>Baz</p>"
952 );
953 }
954
955 #[test]
956 fn test_linebreaksbr() {
957 assert_eq!(linebreaksbr("Foo\nBar").unwrap().to_string(), "Foo<br/>Bar");
958 assert_eq!(
959 linebreaksbr("Foo\nBar\n\nBaz").unwrap().to_string(),
960 "Foo<br/>Bar<br/><br/>Baz"
961 );
962 }
963
964 #[test]
965 fn test_paragraphbreaks() {
966 assert_eq!(
967 paragraphbreaks("Foo\nBar Baz").unwrap().to_string(),
968 "<p>Foo\nBar Baz</p>"
969 );
970 assert_eq!(
971 paragraphbreaks("Foo\nBar\n\nBaz").unwrap().to_string(),
972 "<p>Foo\nBar</p><p>Baz</p>"
973 );
974 assert_eq!(
975 paragraphbreaks("Foo\n\n\n\n\nBar\n\nBaz")
976 .unwrap()
977 .to_string(),
978 "<p>Foo</p><p>\nBar</p><p>Baz</p>"
979 );
980 }
981
982 #[test]
983 fn test_lower() {
984 assert_eq!(lower("Foo").unwrap().to_string(), "foo");
985 assert_eq!(lower("FOO").unwrap().to_string(), "foo");
986 assert_eq!(lower("FooBar").unwrap().to_string(), "foobar");
987 assert_eq!(lower("foo").unwrap().to_string(), "foo");
988 }
989
990 #[test]
991 fn test_upper() {
992 assert_eq!(upper("Foo").unwrap().to_string(), "FOO");
993 assert_eq!(upper("FOO").unwrap().to_string(), "FOO");
994 assert_eq!(upper("FooBar").unwrap().to_string(), "FOOBAR");
995 assert_eq!(upper("foo").unwrap().to_string(), "FOO");
996 }
997
998 #[test]
999 fn test_trim() {
1000 assert_eq!(trim(" Hello\tworld\t").unwrap().to_string(), "Hello\tworld");
1001 }
1002
1003 #[test]
1004 fn test_indent() {
1005 assert_eq!(
1006 indent("hello", 2, false, false).unwrap().to_string(),
1007 "hello"
1008 );
1009 assert_eq!(
1010 indent("hello\n", 2, false, false).unwrap().to_string(),
1011 "hello\n"
1012 );
1013 assert_eq!(
1014 indent("hello\nfoo", 2, false, false).unwrap().to_string(),
1015 "hello\n foo"
1016 );
1017 assert_eq!(
1018 indent("hello\nfoo\n bar", 4, false, false)
1019 .unwrap()
1020 .to_string(),
1021 "hello\n foo\n bar"
1022 );
1023 assert_eq!(
1024 indent("hello", 267_332_238_858, false, false)
1025 .unwrap()
1026 .to_string(),
1027 "hello"
1028 );
1029
1030 assert_eq!(
1031 indent("hello\n\n bar", 4, false, false)
1032 .unwrap()
1033 .to_string(),
1034 "hello\n\n bar"
1035 );
1036 assert_eq!(
1037 indent("hello\n\n bar", 4, false, true).unwrap().to_string(),
1038 "hello\n \n bar"
1039 );
1040 assert_eq!(
1041 indent("hello\n\n bar", 4, true, false).unwrap().to_string(),
1042 " hello\n\n bar"
1043 );
1044 assert_eq!(
1045 indent("hello\n\n bar", 4, true, true).unwrap().to_string(),
1046 " hello\n \n bar"
1047 );
1048 }
1049
1050 #[test]
1051 fn test_indent_str() {
1052 assert_eq!(
1053 indent("hello\n\n bar", "❗❓", false, false)
1054 .unwrap()
1055 .to_string(),
1056 "hello\n\n❗❓ bar"
1057 );
1058 assert_eq!(
1059 indent("hello\n\n bar", "❗❓", false, true)
1060 .unwrap()
1061 .to_string(),
1062 "hello\n❗❓\n❗❓ bar"
1063 );
1064 assert_eq!(
1065 indent("hello\n\n bar", "❗❓", true, false)
1066 .unwrap()
1067 .to_string(),
1068 "❗❓hello\n\n❗❓ bar"
1069 );
1070 assert_eq!(
1071 indent("hello\n\n bar", "❗❓", true, true)
1072 .unwrap()
1073 .to_string(),
1074 "❗❓hello\n❗❓\n❗❓ bar"
1075 );
1076 }
1077
1078 #[test]
1079 #[allow(clippy::arc_with_non_send_sync)] #[allow(clippy::type_complexity)] fn test_indent_complicated() {
1082 use std::boxed::Box;
1083 use std::cell::{RefCell, RefMut};
1084 use std::rc::Rc;
1085 use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockWriteGuard};
1086
1087 let prefix = Mutex::new(Box::pin("❗❓".to_owned()));
1088 let prefix = RefCell::new(Arc::new(prefix.try_lock().unwrap()));
1089 let prefix = RwLock::new(Rc::new(prefix.borrow_mut()));
1090 let prefix: RwLockWriteGuard<'_, Rc<RefMut<'_, Arc<MutexGuard<'_, Pin<Box<String>>>>>>> =
1091 prefix.try_write().unwrap();
1092
1093 assert_eq!(
1094 indent("hello\n\n bar", &prefix, false, false)
1095 .unwrap()
1096 .to_string(),
1097 "hello\n\n❗❓ bar"
1098 );
1099 assert_eq!(
1100 indent("hello\n\n bar", &prefix, false, true)
1101 .unwrap()
1102 .to_string(),
1103 "hello\n❗❓\n❗❓ bar"
1104 );
1105 assert_eq!(
1106 indent("hello\n\n bar", &prefix, true, false)
1107 .unwrap()
1108 .to_string(),
1109 "❗❓hello\n\n❗❓ bar"
1110 );
1111 assert_eq!(
1112 indent("hello\n\n bar", &prefix, true, true)
1113 .unwrap()
1114 .to_string(),
1115 "❗❓hello\n❗❓\n❗❓ bar"
1116 );
1117 }
1118
1119 #[test]
1120 fn test_capitalize() {
1121 assert_eq!(capitalize("foo").unwrap().to_string(), "Foo".to_string());
1122 assert_eq!(capitalize("f").unwrap().to_string(), "F".to_string());
1123 assert_eq!(capitalize("fO").unwrap().to_string(), "Fo".to_string());
1124 assert_eq!(capitalize("").unwrap().to_string(), String::new());
1125 assert_eq!(capitalize("FoO").unwrap().to_string(), "Foo".to_string());
1126 assert_eq!(
1127 capitalize("foO BAR").unwrap().to_string(),
1128 "Foo bar".to_string()
1129 );
1130 assert_eq!(
1131 capitalize("äØÄÅÖ").unwrap().to_string(),
1132 "Äøäåö".to_string()
1133 );
1134 assert_eq!(capitalize("ß").unwrap().to_string(), "SS".to_string());
1135 assert_eq!(capitalize("ßß").unwrap().to_string(), "SSß".to_string());
1136 }
1137
1138 #[test]
1139 fn test_wordcount() {
1140 for &(word, count) in &[
1141 ("", 0),
1142 (" \n\t", 0),
1143 ("foo", 1),
1144 ("foo bar", 2),
1145 ("foo bar", 2),
1146 ] {
1147 let w = wordcount(word);
1148 let _ = w.to_string();
1149 assert_eq!(w.into_count(), count, "fmt: {word:?}");
1150
1151 let w = wordcount(word);
1152 w.write_into(&mut String::new(), NO_VALUES).unwrap();
1153 assert_eq!(w.into_count(), count, "FastWritable: {word:?}");
1154 }
1155 }
1156
1157 #[test]
1158 fn test_title() {
1159 assert_eq!(&title("").unwrap().to_string(), "");
1160 assert_eq!(&title(" \n\t").unwrap().to_string(), " \n\t");
1161 assert_eq!(&title("foo").unwrap().to_string(), "Foo");
1162 assert_eq!(&title(" foo").unwrap().to_string(), " Foo");
1163 assert_eq!(&title("foo bar").unwrap().to_string(), "Foo Bar");
1164 assert_eq!(&title("foo bar ").unwrap().to_string(), "Foo Bar ");
1165 assert_eq!(&title("fOO").unwrap().to_string(), "Foo");
1166 assert_eq!(&title("fOo BaR").unwrap().to_string(), "Foo Bar");
1167 assert_eq!(&title("foo\r\nbar").unwrap().to_string(), "Foo\r\nBar");
1168 assert_eq!(
1169 &title("Fo\x0boo\x0coO\u{2002}OO\u{3000}baR")
1170 .unwrap()
1171 .to_string(),
1172 "Fo\x0bOo\x0cOo\u{2002}Oo\u{3000}Bar"
1173 );
1174 }
1175
1176 #[test]
1177 fn fuzzed_indent_filter() {
1178 let s = "hello\nfoo\nbar".to_string().repeat(1024);
1179 assert_eq!(indent(s.clone(), 4, false, false).unwrap().to_string(), s);
1180 }
1181}