1use core::fmt::{self, Write as _};
4
5use crate::std::string::String;
6
7#[must_use]
18#[expect(
19 clippy::expect_used,
20 reason = "match format! semantics for caller-provided formatting implementations"
21)]
22pub fn format_with_capacity(capacity: usize, args: fmt::Arguments<'_>) -> String {
23 let mut output = String::with_capacity(capacity);
24 output
25 .write_fmt(args)
26 .expect("formatting into a String cannot fail");
27 output
28}
29
30pub fn try_format_into<'a>(
37 output: &'a mut String,
38 args: fmt::Arguments<'_>,
39) -> Result<&'a str, fmt::Error> {
40 output.clear();
41 output.write_fmt(args)?;
42 Ok(output.as_str())
43}
44
45pub fn display_fn<F>(formatter: F) -> DisplayFn<F> {
50 DisplayFn(formatter)
51}
52
53#[derive(Clone, Copy)]
55pub struct DisplayFn<F>(F);
56
57impl<F> fmt::Display for DisplayFn<F>
58where
59 F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
60{
61 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
62 (self.0)(formatter)
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use core::fmt;
69
70 use super::*;
71
72 #[test]
73 fn formats_with_requested_capacity() {
74 let output = format_with_capacity(32, format_args!("hello {value}", value = 42));
75
76 assert_eq!(output, "hello 42");
77 assert!(output.capacity() >= 32);
78 }
79
80 #[test]
81 fn formats_into_reused_string() {
82 let mut output = String::with_capacity(64);
83 output.push_str("old contents");
84 let allocation = output.as_ptr();
85
86 let formatted =
87 try_format_into(&mut output, format_args!("new {value}", value = "contents")).unwrap();
88
89 assert_eq!(formatted, "new contents");
90 assert_eq!(output.as_ptr(), allocation);
91 }
92
93 #[test]
94 fn formatting_into_reused_string_propagates_display_errors() {
95 struct Fails;
96
97 impl fmt::Display for Fails {
98 fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
99 Err(fmt::Error)
100 }
101 }
102
103 let mut output = String::from("old contents");
104 let value = Fails;
105 let error = try_format_into(&mut output, format_args!("prefix {value}")).unwrap_err();
106
107 assert_eq!(error, fmt::Error);
108 assert_eq!(output, "prefix ");
109 }
110
111 #[test]
112 fn display_fn_defers_display_formatting() {
113 let value =
114 display_fn(|formatter: &mut fmt::Formatter<'_>| formatter.write_str("deferred"));
115
116 assert_eq!(value.to_string(), "deferred");
117 }
118}