const_format/fmt/
str_writer.rs

1use super::{Error, Formatter, FormattingFlags, StrWriterMut, Utf8Encoding};
2
3use core::marker::PhantomData;
4
5////////////////////////////////////////////////////////////////////////////////
6
7/// A wrapper over an array usable to build up a `&str` at compile-time.
8///
9/// # Calling methods
10///
11/// [Certain `StrWriter` methods](#certain-methods) require
12/// a `StrWriter<[u8]>` to be called,
13/// and since constructing `StrWriter` from an array produces a `StrWriter<[u8; N]>`,
14/// it must be cast to call them.
15///
16/// `StrWriter`'s type parameter defaults to `[u8]`,
17/// so every instance of a `StrWriter` as a *type* is a `StrWriter<[u8]>`.
18///
19/// Example of casting it:
20///
21/// ```rust
22/// # use const_format::StrWriter;
23/// let writer: &mut StrWriter<[u8; 8]> = &mut StrWriter::new([0; 8]);
24///
25/// // Casts `&StrWriter<[u8; 8]>` to `&StrWriter`
26/// writer.unsize();
27///
28/// // Casts `&StrWriter<[u8; 8]>` to `&StrWriter`
29/// writer.r();
30///
31/// // Coerces the `&mut StrWriter<[u8; 8]>` to `&mut StrWriter`
32/// let _writer: &mut StrWriter = writer;
33///
34/// // Casts `&mut StrWriter<[u8; 8]>` to `StrWriterMut<'_>`,
35/// // which defines methods for mutating `StrWriter`
36/// let _writer = writer.as_mut();
37///
38/// # drop(writer);
39/// ```
40///
41/// # StrWriterMut
42///
43/// `StrWriter` can be borrowed into a [`StrWriterMut`],
44/// which provides methods for writing a formatted string.
45///
46/// Example:
47///
48/// ```rust
49/// use const_format::StrWriter;
50///
51/// let mut buffer: &mut StrWriter = &mut StrWriter::new([0; 100]);
52///
53/// let mut writer = buffer.as_mut();
54/// writer.write_str("Your password is: ");
55/// writer.write_str_debug("PASSWORD");
56///
57/// assert_eq!(writer.as_str(), r#"Your password is: "PASSWORD""#);
58///
59/// ```
60///
61/// # Examples
62///
63/// ### Formatting into associated constant
64///
65/// This example shows how you can construct a formatted `&'static str` from associated constants.
66///
67/// ```rust
68///
69/// use const_format::{StrWriter, writec, unwrap};
70///
71/// trait Num {
72///     const V: u32;
73/// }
74///
75/// struct Two;
76///
77/// impl Num for Two {
78///     const V: u32 = 2;
79/// }
80///
81/// struct Three;
82///
83/// impl Num for Three {
84///     const V: u32 = 3;
85/// }
86///
87/// struct Mul<L, R>(L, R);
88///
89/// const fn compute_str(l: u32, r: u32) -> StrWriter<[u8; 128]> {
90///     let mut writer = StrWriter::new([0; 128]);
91///     unwrap!(writec!(writer, "{} * {} == {}", l, r, l * r ));
92///     writer
93/// }
94///
95/// impl<L: Num, R: Num> Mul<L, R> {
96///     const __STR: &'static StrWriter<[u8]> = &compute_str(L::V, R::V);
97///     const STR: &'static str = Self::__STR.as_str_alt();
98/// }
99///
100/// assert_eq!(Mul::<Two,Three>::STR, "2 * 3 == 6");
101/// assert_eq!(Mul::<Three,Three>::STR, "3 * 3 == 9");
102///
103/// ```
104///
105/// [`StrWriterMut`]: ./struct.StrWriterMut.html
106///
107#[derive(Debug, Copy, Clone)]
108pub struct StrWriter<A: ?Sized = [u8]> {
109    pub(super) len: usize,
110    pub(super) buffer: A,
111}
112
113impl<A> StrWriter<A> {
114    /// Constructs a `StrWriter` from a `u8` array
115    pub const fn new(array: A) -> Self {
116        Self {
117            len: 0,
118            buffer: array,
119        }
120    }
121}
122
123impl<A: ?Sized> StrWriter<A> {
124    /// Accesses the underlying buffer immutably.
125    ///
126    /// # Example
127    ///
128    /// ```rust
129    /// use const_format::StrWriter;
130    ///
131    /// let buffer: &mut StrWriter = &mut StrWriter::new([0; 7]);
132    /// assert_eq!(buffer.buffer(), &[0; 7]);
133    ///
134    /// buffer.as_mut().write_str("foo")?;
135    /// assert_eq!(buffer.buffer(), b"foo\0\0\0\0");
136    ///
137    /// buffer.as_mut().write_str("bar")?;
138    /// assert_eq!(buffer.buffer(), b"foobar\0");
139    ///
140    /// # Ok::<(), const_format::Error>(())
141    /// ```
142    #[inline(always)]
143    pub const fn buffer(&self) -> &A {
144        &self.buffer
145    }
146
147    /// How long the string this wrote is.
148    ///
149    /// # Example
150    ///
151    /// ```rust
152    /// use const_format::StrWriter;
153    ///
154    /// let buffer: &mut StrWriter = &mut StrWriter::new([0; 64]);
155    /// assert_eq!(buffer.len(), 0);
156    ///
157    /// buffer.as_mut().write_str("foo")?;
158    /// assert_eq!(buffer.len(), 3);
159    ///
160    /// buffer.as_mut().write_str("bar")?;
161    /// assert_eq!(buffer.len(), 6);
162    ///
163    /// # Ok::<(), const_format::Error>(())
164    /// ```
165    #[inline(always)]
166    pub const fn len(&self) -> usize {
167        self.len
168    }
169
170    /// Checks whether the string this wrote is empty.
171    ///
172    /// # Example
173    ///
174    /// ```rust
175    /// use const_format::StrWriter;
176    ///
177    /// let buffer: &mut StrWriter = &mut StrWriter::new([0; 64]);
178    /// assert!( buffer.is_empty() );
179    ///
180    /// buffer.as_mut().write_str("foo")?;
181    /// assert!( !buffer.is_empty() );
182    ///
183    /// # Ok::<(), const_format::Error>(())
184    /// ```
185    #[inline]
186    pub const fn is_empty(&self) -> bool {
187        self.len == 0
188    }
189}
190
191/// <span id="certain-methods"></span>
192impl StrWriter {
193    /// Gets the maximum length for a string written into this.
194    ///
195    /// Trying to write more that the capacity causes an error,
196    /// returning back an `Err(Error::NotEnoughSpace)`
197    ///
198    /// # Example
199    ///
200    /// ```rust
201    /// use const_format::{Error, StrWriter};
202    ///
203    /// let buffer: &mut StrWriter = &mut StrWriter::new([0; 64]);
204    /// assert_eq!(buffer.capacity(), 64);
205    ///
206    /// buffer.as_mut().write_ascii_repeated(b'A', 64)?;
207    /// assert_eq!(buffer.capacity(), 64);
208    ///
209    /// assert_eq!(buffer.as_mut().write_str("-").unwrap_err(), Error::NotEnoughSpace);
210    /// assert_eq!(buffer.capacity(), 64);
211    ///
212    /// # Ok::<(), const_format::Error>(())
213    /// ```
214    #[inline(always)]
215    pub const fn capacity(&self) -> usize {
216        self.buffer.len()
217    }
218
219    /// Checks how many more bytes can be written.
220    ///
221    /// # Example
222    ///
223    /// ```rust
224    /// use const_format::{Error, StrWriter};
225    ///
226    /// let buffer: &mut StrWriter = &mut StrWriter::new([0; 64]);
227    /// assert_eq!(buffer.remaining_capacity(), 64);
228    ///
229    /// buffer.as_mut().write_str("foo")?;
230    /// assert_eq!(buffer.remaining_capacity(), 61);
231    ///
232    /// buffer.as_mut().write_ascii_repeated(b'a', 61)?;
233    /// assert_eq!(buffer.remaining_capacity(), 0);
234    ///
235    /// assert_eq!(buffer.as_mut().write_str(" ").unwrap_err(), Error::NotEnoughSpace);
236    ///
237    /// # Ok::<(), const_format::Error>(())
238    /// ```
239    #[inline]
240    pub const fn remaining_capacity(&self) -> usize {
241        self.buffer.len() - self.len
242    }
243
244    /// Truncates this `StrWriter` to `length`.
245    ///
246    /// If `length` is greater than the current length, this does nothing.
247    ///
248    /// # Errors
249    ///
250    /// Returns an `Error::NotOnCharBoundary` if `length` is not on a char boundary.
251    ///
252    /// # Example
253    ///
254    /// ```rust
255    /// use const_format::{Error, StrWriter};
256    ///
257    /// let buffer: &mut StrWriter = &mut StrWriter::new([0; 64]);
258    ///
259    /// buffer.as_mut().write_str("foo bâr baz");
260    /// assert_eq!(buffer.as_str(), "foo bâr baz");
261    ///
262    /// assert_eq!(buffer.truncate(6).unwrap_err(), Error::NotOnCharBoundary);
263    ///
264    /// buffer.truncate(3)?;
265    /// assert_eq!(buffer.as_str(), "foo");
266    ///
267    /// buffer.as_mut().write_str("ooooooo");
268    /// assert_eq!(buffer.as_str(), "fooooooooo");
269    ///
270    /// # Ok::<(), const_format::Error>(())
271    /// ```
272    #[inline]
273    pub const fn truncate(&mut self, length: usize) -> Result<(), Error> {
274        self.as_mut().truncate(length)
275    }
276
277    /// Truncates this `StrWriter` to length 0.
278    ///
279    /// # Example
280    ///
281    /// ```rust
282    /// use const_format::{Error, StrWriter};
283    ///
284    /// let buffer: &mut StrWriter = &mut StrWriter::new([0; 64]);
285    ///
286    /// buffer.as_mut().write_str("foo")?;
287    /// assert_eq!(buffer.as_str(), "foo");
288    ///
289    /// buffer.clear();
290    /// assert_eq!(buffer.as_str(), "");
291    /// assert!(buffer.is_empty());
292    ///
293    /// buffer.as_mut().write_str("bar");
294    /// assert_eq!(buffer.as_str(), "bar");
295    ///
296    /// # Ok::<(), const_format::Error>(())
297    /// ```
298    #[inline]
299    pub const fn clear(&mut self) {
300        self.len = 0;
301    }
302
303    /// Gets the written part of this `StrWriter` as a `&[u8]`
304    ///
305    /// The slice is guaranteed to be valid utf8, so this is mostly for convenience.
306    ///
307    /// ### Runtime
308    ///
309    /// If the "rust_1_64" feature is disabled,
310    /// this takes time proportional to `self.capacity() - self.len()`.
311    ///
312    /// If the "rust_1_64" feature is enabled, it takes constant time to run.
313    ///
314    /// # Example
315    ///
316    /// ```rust
317    ///
318    /// use const_format::{StrWriter, StrWriterMut};
319    ///
320    /// const fn slice() -> StrWriter<[u8; 64]> {
321    ///     let mut buffer = StrWriter::new([0; 64]);
322    ///     let mut writer = StrWriterMut::new(&mut buffer);
323    ///     writer.write_str("Hello, World!");
324    ///     buffer
325    /// }
326    ///
327    /// const SLICE: &[u8] = {
328    ///     const PROM: &'static StrWriter = &slice();
329    ///     PROM.as_bytes_alt()
330    /// };
331    ///
332    ///
333    /// assert_eq!(SLICE, "Hello, World!".as_bytes());
334    ///
335    /// ```
336    #[inline(always)]
337    pub const fn as_bytes_alt(&self) -> &[u8] {
338        crate::utils::slice_up_to_len_alt(&self.buffer, self.len)
339    }
340
341    /// Gets the written part of this `StrWriter` as a `&str`
342    ///
343    /// ### Runtime
344    ///
345    /// If the "rust_1_64" feature is disabled,
346    /// this takes time proportional to `self.capacity() - self.len()`.
347    ///
348    /// If the "rust_1_64" feature is enabled, it takes constant time to run.
349    ///
350    /// # Example
351    ///
352    /// ```rust
353    ///
354    /// use const_format::StrWriter;
355    /// use const_format::{unwrap, writec};
356    ///
357    ///
358    /// const CAP: usize = 128;
359    ///
360    /// const __STR: &StrWriter = &{
361    ///     let mut writer =  StrWriter::new([0; CAP]);
362    ///
363    ///     // Writing the array with debug formatting, and the integers with hexadecimal formatting.
364    ///     unwrap!(writec!(writer, "{:X}", [3u32, 5, 8, 13, 21, 34]));
365    ///
366    ///     writer
367    /// };
368    ///
369    /// const STR: &str = __STR.as_str_alt();
370    ///
371    /// fn main() {
372    ///     assert_eq!(STR, "[3, 5, 8, D, 15, 22]");
373    /// }
374    /// ```
375    #[inline(always)]
376    pub const fn as_str_alt(&self) -> &str {
377        // All the methods that modify the buffer must ensure utf8 validity,
378        // only methods from this module need to ensure this.
379        unsafe { core::str::from_utf8_unchecked(self.as_bytes_alt()) }
380    }
381
382    conditionally_const! {
383        feature = "rust_1_64";
384        /// Gets the written part of this `StrWriter` as a `&str`
385        ///
386        /// ### Constness
387        ///
388        /// This can be called in const contexts by enabling the "rust_1_64" feature.
389        ///
390        /// ### Alternative
391        ///
392        /// You can also use the [`as_str_alt`](Self::as_str_alt) method,
393        /// which is always available,
394        /// but takes linear time to run when the "rust_1_64" feature
395        /// is disabled.
396        ///
397        #[inline(always)]
398        pub fn as_str(&self) -> &str {
399            // All the methods that modify the buffer must ensure utf8 validity,
400            // only methods from this module need to ensure this.
401            unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
402        }
403
404        /// Gets the written part of this `StrWriter` as a `&[u8]`
405        ///
406        /// The slice is guaranteed to be valid utf8, so this is mostly for convenience.
407        ///
408        /// ### Constness
409        ///
410        /// This can be called in const contexts by enabling the "rust_1_64" feature.
411        ///
412        /// # Example
413        ///
414        /// ```rust
415        /// use const_format::StrWriter;
416        ///
417        /// let buffer: &mut StrWriter = &mut StrWriter::new([0; 64]);
418        ///
419        /// buffer.as_mut().write_str("Hello, World!");
420        ///
421        /// assert_eq!(buffer.as_bytes(), "Hello, World!".as_bytes());
422        ///
423        /// ```
424        #[inline(always)]
425        pub fn as_bytes(&self) -> &[u8] {
426            crate::utils::slice_up_to_len(&self.buffer, self.len)
427        }
428    }
429
430    /// Borrows this `StrWriter<[u8]>` into a `StrWriterMut`,
431    /// most useful for calling the `write_*` methods.
432    ///
433    /// ```rust
434    /// use const_format::StrWriter;
435    ///
436    /// let buffer: &mut StrWriter = &mut StrWriter::new([0; 64]);
437    ///
438    /// buffer.as_mut().write_str_range("trust", 1..usize::MAX);
439    ///
440    /// assert_eq!(buffer.as_str(), "rust");
441    ///
442    /// ```
443    #[inline(always)]
444    pub const fn as_mut(&mut self) -> StrWriterMut<'_> {
445        StrWriterMut {
446            len: &mut self.len,
447            buffer: &mut self.buffer,
448            _encoding: PhantomData,
449        }
450    }
451
452    /// Constructs a [`Formatter`] that writes into this `StrWriter`,
453    /// which can be passed to debug and display formatting methods.
454    ///
455    /// # Example
456    ///
457    /// ```rust
458    ///
459    /// use const_format::{Error, Formatter, FormattingFlags, StrWriter, call_debug_fmt};
460    ///
461    /// use std::ops::Range;
462    ///
463    /// const fn range_debug_fmt(
464    ///     slice: &[Range<usize>],
465    ///     f: &mut Formatter<'_>
466    /// ) -> Result<(), Error> {
467    ///     // We need this macro to debug format arrays of non-primitive types
468    ///     // Also, it implicitly returns a `const_format::Error` on error.
469    ///     call_debug_fmt!(array, slice, f);
470    ///     Ok(())
471    /// }
472    ///
473    /// fn main() -> Result<(), Error> {
474    ///     let buffer: &mut StrWriter = &mut StrWriter::new([0; 64]);
475    ///
476    ///     range_debug_fmt(
477    ///         &[0..14, 14..31, 31..48],
478    ///         &mut buffer.make_formatter(FormattingFlags::new().set_binary())
479    ///     )?;
480    ///    
481    ///     assert_eq!(buffer.as_str(), "[0..1110, 1110..11111, 11111..110000]");
482    ///
483    ///     Ok(())
484    /// }
485    /// ```
486    ///
487    /// [`Formatter`]: ./struct.Formatter.html
488    #[inline(always)]
489    pub const fn make_formatter(&mut self, flags: FormattingFlags) -> Formatter<'_> {
490        Formatter::from_sw_mut(
491            StrWriterMut::<Utf8Encoding> {
492                len: &mut self.len,
493                buffer: &mut self.buffer,
494                _encoding: PhantomData,
495            },
496            flags,
497        )
498    }
499}
500
501impl<const N: usize> StrWriter<[u8; N]> {
502    /// Casts a `&StrWriter<[u8; N]>` to a `&StrWriter<[u8]>`,
503    /// for calling methods defined on `StrWriter<[u8]>` (most of them).
504    ///
505    /// # Example
506    ///
507    /// ```rust
508    /// use const_format::StrWriter;
509    ///
510    /// let mut buffer = StrWriter::new([0; 64]);
511    ///
512    /// buffer.as_mut().write_str("Hello,");
513    /// buffer.as_mut().write_str(" world!");
514    ///
515    /// assert_eq!(buffer.r().as_str(), "Hello, world!");
516    ///
517    /// ```
518    ///
519    #[inline(always)]
520    pub const fn r(&self) -> &StrWriter<[u8]> {
521        self
522    }
523    /// Casts a `&StrWriter<[u8; N]>` to a `&StrWriter<[u8]>`,
524    /// for calling methods defined on `StrWriter<[u8]>` (most of them).
525    ///
526    /// # Example
527    ///
528    /// ```rust
529    /// use const_format::StrWriter;
530    ///
531    /// let mut buffer = StrWriter::new([0; 64]);
532    ///
533    /// buffer.as_mut().write_str("Hello,");
534    /// buffer.as_mut().write_str(" world!");
535    ///
536    /// assert_eq!(buffer.unsize().as_str(), "Hello, world!");
537    ///
538    /// ```
539    ///
540    #[inline(always)]
541    pub const fn unsize(&self) -> &StrWriter<[u8]> {
542        self
543    }
544
545    /// Borrows this `StrWriter<[u8; N]>` into a `StrWriterMut`.
546    ///
547    /// # Example
548    ///
549    /// ```rust
550    /// use const_format::StrWriter;
551    ///
552    /// let mut buffer = StrWriter::new([0; 64]);
553    ///
554    /// buffer.as_mut().write_str_range("trust", 1..usize::MAX);
555    ///
556    /// assert_eq!(buffer.r().as_str(), "rust");
557    ///
558    /// ```
559    #[inline(always)]
560    pub const fn as_mut(&mut self) -> StrWriterMut<'_> {
561        StrWriterMut {
562            len: &mut self.len,
563            buffer: &mut self.buffer,
564            _encoding: PhantomData,
565        }
566    }
567}
568
569impl<A: ?Sized> StrWriter<A> {
570    /// For borrowing this mutably in macros, without getting nested mutable references.
571    #[inline(always)]
572    pub const fn borrow_mutably(&mut self) -> &mut Self {
573        self
574    }
575}