rune_alloc/fmt/
mod.rs

1//! Built-in formatting utilities.
2
3mod impls;
4
5use core::fmt::{self, Arguments};
6
7use crate::borrow::TryToOwned;
8use crate::error::Error;
9use crate::string::String;
10
11/// Fallible write formatting implementation.
12pub trait TryWrite {
13    /// Writes a string slice into this writer, returning whether the write
14    /// succeeded.
15    ///
16    /// This method can only succeed if the entire string slice was successfully
17    /// written, and this method will not return until all data has been
18    /// written or an error occurs.
19    ///
20    /// # Errors
21    ///
22    /// This function will return an instance of [`Error`] on error.
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use rune::alloc::fmt::TryWrite;
28    /// use rune::alloc::{String, Error};
29    ///
30    /// fn writer<W>(f: &mut W, s: &str) -> Result<(), Error>
31    /// where
32    ///     W: ?Sized + TryWrite,
33    /// {
34    ///     f.try_write_str(s)
35    /// }
36    ///
37    /// let mut buf = String::new();
38    /// writer(&mut buf, "hola")?;
39    /// assert_eq!(&buf, "hola");
40    /// # Ok::<_, rune::alloc::Error>(())
41    /// ```
42    fn try_write_str(&mut self, s: &str) -> Result<(), Error>;
43
44    /// Writes a [`char`] into this writer, returning whether the write succeeded.
45    ///
46    /// A single [`char`] may be encoded as more than one byte.
47    /// This method can only succeed if the entire byte sequence was successfully
48    /// written, and this method will not return until all data has been
49    /// written or an error occurs.
50    ///
51    /// # Errors
52    ///
53    /// This function will return an instance of [`Error`] on error.
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use rune::alloc::fmt::TryWrite;
59    /// use rune::alloc::{String, Error};
60    ///
61    /// fn writer<W>(f: &mut W, c: char) -> Result<(), Error>
62    /// where
63    ///     W: ?Sized + TryWrite,
64    /// {
65    ///     f.try_write_char(c)
66    /// }
67    ///
68    /// let mut buf = String::new();
69    /// writer(&mut buf, 'a')?;
70    /// writer(&mut buf, 'b')?;
71    /// assert_eq!(&buf, "ab");
72    /// # Ok::<_, rune::alloc::Error>(())
73    /// ```
74    #[inline]
75    fn try_write_char(&mut self, c: char) -> Result<(), Error> {
76        self.try_write_str(c.encode_utf8(&mut [0; 4]))
77    }
78
79    #[inline]
80    #[doc(hidden)]
81    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Error> {
82        struct Writer<'a, T>
83        where
84            T: ?Sized,
85        {
86            target: &'a mut T,
87            error: Option<Error>,
88        }
89
90        impl<T> fmt::Write for Writer<'_, T>
91        where
92            T: ?Sized + TryWrite,
93        {
94            #[inline]
95            fn write_str(&mut self, s: &str) -> fmt::Result {
96                if let Err(error) = (*self.target).try_write_str(s) {
97                    self.error = Some(error);
98                }
99
100                Ok(())
101            }
102
103            #[inline]
104            fn write_char(&mut self, c: char) -> fmt::Result {
105                if let Err(error) = (*self.target).try_write_char(c) {
106                    self.error = Some(error);
107                }
108
109                Ok(())
110            }
111        }
112
113        let mut writer = Writer {
114            target: self,
115            error: None,
116        };
117
118        if let Err(fmt::Error) = fmt::write(&mut writer, args) {
119            return Err(Error::FormatError);
120        }
121
122        if let Some(error) = writer.error {
123            Err(error)
124        } else {
125            Ok(())
126        }
127    }
128}
129
130/// The `format` function takes an [`Arguments`] struct and returns the
131/// resulting formatted string.
132///
133/// The [`Arguments`] instance can be created with the [`format_args!`] macro.
134///
135/// # Examples
136///
137/// Basic usage:
138///
139/// ```
140/// use rune::alloc::fmt;
141///
142/// let s = fmt::try_format(format_args!("Hello, {}!", "world"))?;
143/// assert_eq!(s, "Hello, world!");
144/// # Ok::<_, rune::alloc::Error>(())
145/// ```
146///
147/// Please note that using [`try_format!`] might be preferable. Example:
148///
149/// ```
150/// use rune::alloc::try_format;
151///
152/// let s = try_format!("Hello, {}!", "world");
153/// assert_eq!(s, "Hello, world!");
154/// # Ok::<_, rune::alloc::Error>(())
155/// ```
156///
157/// [`format_args!`]: core::format_args
158/// [`try_format!`]: try_format!
159#[inline]
160pub fn try_format(args: Arguments<'_>) -> Result<String, Error> {
161    #[cfg(rune_nightly)]
162    fn estimated_capacity(args: &Arguments<'_>) -> usize {
163        args.estimated_capacity()
164    }
165
166    #[cfg(not(rune_nightly))]
167    fn estimated_capacity(_: &Arguments<'_>) -> usize {
168        0
169    }
170
171    fn format_inner(args: Arguments<'_>) -> Result<String, Error> {
172        let capacity = estimated_capacity(&args);
173        let mut output = String::try_with_capacity(capacity)?;
174        output.write_fmt(args)?;
175        Ok(output)
176    }
177
178    match args.as_str() {
179        Some(string) => string.try_to_owned(),
180        None => format_inner(args),
181    }
182}