use alloc::str;
use alloc::string::String;
use core::convert::Infallible;
use core::fmt::{self, Write};
use crate::{FastWritable, Result};
macro_rules! try_to_str {
($src:expr => $buffer:ident) => {
match format_args!("{}", $src) {
args => {
if let Some(s) = args.as_str() {
s
} else {
$buffer = String::new();
$buffer.write_fmt(args)?;
&$buffer
}
}
}
};
}
pub fn fmt() {}
pub fn format() {}
#[inline]
pub fn lower<S: fmt::Display>(source: S) -> Result<Lower<S>, Infallible> {
Ok(Lower(source))
}
pub struct Lower<S>(S);
impl<S: fmt::Display> fmt::Display for Lower<S> {
#[inline]
fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buffer;
flush_lower(dest, try_to_str!(self.0 => buffer))
}
}
impl<S: FastWritable> FastWritable for Lower<S> {
#[inline]
fn write_into(
&self,
dest: &mut dyn fmt::Write,
values: &dyn crate::Values,
) -> crate::Result<()> {
let mut buffer = String::new();
self.0.write_into(&mut buffer, values)?;
Ok(flush_lower(dest, &buffer)?)
}
}
fn flush_lower(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
dest.write_str(&s.to_lowercase())
}
#[inline]
pub fn lowercase<S: fmt::Display>(source: S) -> Result<Lower<S>, Infallible> {
lower(source)
}
#[inline]
pub fn upper<S: fmt::Display>(source: S) -> Result<Upper<S>, Infallible> {
Ok(Upper(source))
}
pub struct Upper<S>(S);
impl<S: fmt::Display> fmt::Display for Upper<S> {
#[inline]
fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buffer;
flush_upper(dest, try_to_str!(self.0 => buffer))
}
}
impl<S: FastWritable> FastWritable for Upper<S> {
#[inline]
fn write_into(
&self,
dest: &mut dyn fmt::Write,
values: &dyn crate::Values,
) -> crate::Result<()> {
let mut buffer = String::new();
self.0.write_into(&mut buffer, values)?;
Ok(flush_upper(dest, &buffer)?)
}
}
fn flush_upper(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
dest.write_str(&s.to_uppercase())
}
#[inline]
pub fn uppercase<S: fmt::Display>(source: S) -> Result<Upper<S>, Infallible> {
upper(source)
}
#[inline]
pub fn trim<S: fmt::Display>(source: S) -> Result<Trim<S>, Infallible> {
Ok(Trim(source))
}
pub struct Trim<S>(S);
impl<S: fmt::Display> fmt::Display for Trim<S> {
#[inline]
fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut collector = TrimCollector(String::new());
write!(collector, "{}", self.0)?;
flush_trim(dest, collector)
}
}
impl<S: FastWritable> FastWritable for Trim<S> {
#[inline]
fn write_into(
&self,
dest: &mut dyn fmt::Write,
values: &dyn crate::Values,
) -> crate::Result<()> {
let mut collector = TrimCollector(String::new());
self.0.write_into(&mut collector, values)?;
Ok(flush_trim(dest, collector)?)
}
}
struct TrimCollector(String);
impl fmt::Write for TrimCollector {
fn write_str(&mut self, s: &str) -> fmt::Result {
match self.0.is_empty() {
true => self.0.write_str(s.trim_start()),
false => self.0.write_str(s),
}
}
}
fn flush_trim(dest: &mut (impl fmt::Write + ?Sized), collector: TrimCollector) -> fmt::Result {
dest.write_str(collector.0.trim_end())
}
#[inline]
pub fn capitalize<S: fmt::Display>(source: S) -> Result<Capitalize<S>, Infallible> {
Ok(Capitalize(source))
}
pub struct Capitalize<S>(S);
impl<S: fmt::Display> fmt::Display for Capitalize<S> {
#[inline]
fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buffer;
flush_capitalize(dest, try_to_str!(self.0 => buffer))
}
}
impl<S: FastWritable> FastWritable for Capitalize<S> {
#[inline]
fn write_into(
&self,
dest: &mut dyn fmt::Write,
values: &dyn crate::Values,
) -> crate::Result<()> {
let mut buffer = String::new();
self.0.write_into(&mut buffer, values)?;
Ok(flush_capitalize(dest, &buffer)?)
}
}
fn flush_capitalize(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
let mut chars = s.chars();
if let Some(c) = chars.next() {
write!(
dest,
"{}{}",
c.to_uppercase(),
chars.as_str().to_lowercase()
)
} else {
Ok(())
}
}
#[inline]
pub fn title<S: fmt::Display>(source: S) -> Result<Title<S>, Infallible> {
Ok(Title(source))
}
pub struct Title<S>(S);
impl<S: fmt::Display> fmt::Display for Title<S> {
#[inline]
fn fmt(&self, dest: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buffer;
flush_title(dest, try_to_str!(self.0 => buffer))
}
}
impl<S: FastWritable> FastWritable for Title<S> {
#[inline]
fn write_into(
&self,
dest: &mut dyn fmt::Write,
values: &dyn crate::Values,
) -> crate::Result<()> {
let mut buffer = String::new();
self.0.write_into(&mut buffer, values)?;
Ok(flush_title(dest, &buffer)?)
}
}
fn flush_title(dest: &mut (impl fmt::Write + ?Sized), s: &str) -> fmt::Result {
for word in s.split_inclusive(char::is_whitespace) {
flush_capitalize(dest, word)?;
}
Ok(())
}
#[inline]
pub fn titlecase<S: fmt::Display>(source: S) -> Result<Title<S>, Infallible> {
title(source)
}
#[cfg(test)]
mod tests {
use alloc::string::ToString;
use super::*;
#[test]
fn test_lower() {
assert_eq!(lower("Foo").unwrap().to_string(), "foo");
assert_eq!(lower("FOO").unwrap().to_string(), "foo");
assert_eq!(lower("FooBar").unwrap().to_string(), "foobar");
assert_eq!(lower("foo").unwrap().to_string(), "foo");
}
#[test]
fn test_upper() {
assert_eq!(upper("Foo").unwrap().to_string(), "FOO");
assert_eq!(upper("FOO").unwrap().to_string(), "FOO");
assert_eq!(upper("FooBar").unwrap().to_string(), "FOOBAR");
assert_eq!(upper("foo").unwrap().to_string(), "FOO");
}
#[test]
fn test_trim() {
assert_eq!(trim(" Hello\tworld\t").unwrap().to_string(), "Hello\tworld");
}
#[test]
fn test_capitalize() {
assert_eq!(capitalize("foo").unwrap().to_string(), "Foo".to_string());
assert_eq!(capitalize("f").unwrap().to_string(), "F".to_string());
assert_eq!(capitalize("fO").unwrap().to_string(), "Fo".to_string());
assert_eq!(capitalize("").unwrap().to_string(), String::new());
assert_eq!(capitalize("FoO").unwrap().to_string(), "Foo".to_string());
assert_eq!(
capitalize("foO BAR").unwrap().to_string(),
"Foo bar".to_string()
);
assert_eq!(
capitalize("äØÄÅÖ").unwrap().to_string(),
"Äøäåö".to_string()
);
assert_eq!(capitalize("ß").unwrap().to_string(), "SS".to_string());
assert_eq!(capitalize("ßß").unwrap().to_string(), "SSß".to_string());
}
#[test]
fn test_title() {
assert_eq!(&title("").unwrap().to_string(), "");
assert_eq!(&title(" \n\t").unwrap().to_string(), " \n\t");
assert_eq!(&title("foo").unwrap().to_string(), "Foo");
assert_eq!(&title(" foo").unwrap().to_string(), " Foo");
assert_eq!(&title("foo bar").unwrap().to_string(), "Foo Bar");
assert_eq!(&title("foo bar ").unwrap().to_string(), "Foo Bar ");
assert_eq!(&title("fOO").unwrap().to_string(), "Foo");
assert_eq!(&title("fOo BaR").unwrap().to_string(), "Foo Bar");
assert_eq!(&title("foo\r\nbar").unwrap().to_string(), "Foo\r\nBar");
assert_eq!(
&title("Fo\x0boo\x0coO\u{2002}OO\u{3000}baR")
.unwrap()
.to_string(),
"Fo\x0bOo\x0cOo\u{2002}Oo\u{3000}Bar"
);
}
}