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