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    where
77        Self: Sized,
78    {
79        struct Writer<'a> {
80            target: &'a mut dyn TryWrite,
81            error: Option<Error>,
82        }
83
84        impl fmt::Write for Writer<'_> {
85            #[inline]
86            fn write_str(&mut self, s: &str) -> fmt::Result {
87                if let Err(error) = (*self.target).try_write_str(s) {
88                    self.error = Some(error);
89                }
90
91                Ok(())
92            }
93
94            #[inline]
95            fn write_char(&mut self, c: char) -> fmt::Result {
96                if let Err(error) = (*self.target).try_write_char(c) {
97                    self.error = Some(error);
98                }
99
100                Ok(())
101            }
102        }
103
104        let mut writer = Writer {
105            target: self,
106            error: None,
107        };
108
109        if let Err(fmt::Error) = fmt::write(&mut writer, args) {
110            return Err(Error::FormatError);
111        }
112
113        if let Some(error) = writer.error {
114            Err(error)
115        } else {
116            Ok(())
117        }
118    }
119}
120
121/// The `format` function takes an [`Arguments`] struct and returns the
122/// resulting formatted string.
123///
124/// The [`Arguments`] instance can be created with the [`format_args!`] macro.
125///
126/// # Examples
127///
128/// Basic usage:
129///
130/// ```
131/// use rune::alloc::fmt;
132///
133/// let s = fmt::try_format(format_args!("Hello, {}!", "world"))?;
134/// assert_eq!(s, "Hello, world!");
135/// # Ok::<_, rune::alloc::Error>(())
136/// ```
137///
138/// Please note that using [`try_format!`] might be preferable. Example:
139///
140/// ```
141/// use rune::alloc::try_format;
142///
143/// let s = try_format!("Hello, {}!", "world");
144/// assert_eq!(s, "Hello, world!");
145/// # Ok::<_, rune::alloc::Error>(())
146/// ```
147///
148/// [`format_args!`]: core::format_args
149/// [`try_format!`]: try_format!
150#[inline]
151pub fn try_format(args: Arguments<'_>) -> Result<String, Error> {
152    #[cfg(rune_nightly)]
153    fn estimated_capacity(args: &Arguments<'_>) -> usize {
154        args.estimated_capacity()
155    }
156
157    #[cfg(not(rune_nightly))]
158    fn estimated_capacity(_: &Arguments<'_>) -> usize {
159        0
160    }
161
162    fn format_inner(args: Arguments<'_>) -> Result<String, Error> {
163        let capacity = estimated_capacity(&args);
164        let mut output = String::try_with_capacity(capacity)?;
165        output.write_fmt(args)?;
166        Ok(output)
167    }
168
169    match args.as_str() {
170        Some(string) => string.try_to_owned(),
171        None => format_inner(args),
172    }
173}