Skip to main content

const_format/fmt/
str_writer_mut.rs

1use crate::{
2    formatting::{
3        hex_as_ascii, ForEscaping, FormattingFlags, HexFormatting, NumberFormatting, FOR_ESCAPING,
4    },
5    utils::{min_usize, saturate_range, Constructor},
6    wrapper_types::{AsciiStr, PWrapper},
7};
8
9use super::{Error, Formatter, StrWriter};
10
11use core::{marker::PhantomData, ops::Range};
12
13/// For writing a formatted string into a `[u8]`.
14///
15/// # Construction
16///
17/// This type can be constructed in these ways:
18///
19/// - From a `&mut StrWriter`, with the [`StrWriter::as_mut`] method.
20///
21/// - From a `&mut StrWriter<_>`, with the [`StrWriterMut::new`] constructor.
22///
23/// - From a pair of `usize` and `[u8]` mutable references,
24/// with the [`from_custom_cleared`] constructor,
25/// or the [`from_custom`] constructor.
26///
27/// # Relation to `Formatter`
28///
29/// This is the type that [`Formatter`] uses to write formatted text to a slice,
30/// sharing all the `write_*` methods,
31/// the difference is that this doesn't store `FormattingFlags`,
32/// so you must pass them to the `write_*_debug` methods.
33///
34/// # Errors
35///
36/// Every single `write_*` method returns an [`Error::NotEnoughSpace`] if
37/// there is not enough space to write the argument, leaving the string itself unmodified.
38///
39/// # Encoding type parameter
40///
41/// The `E` type parameter represents the encoding of the buffer that this
42/// StrWriterMut writes into,
43/// currently only [`Utf8Encoding`] and [`NoEncoding`] are supported.
44///
45/// # Example
46///
47/// This example demonstrates how you can write a formatted string to a `&mut [u8]`,
48/// using a `StrWriterMut`.
49///
50/// ```rust
51///
52/// use const_format::{Error, StrWriterMut, try_, writec};
53///
54/// const fn format_number(number: u32,slice: &mut [u8]) -> Result<usize, Error> {
55///     let mut len = 0;
56///     let mut writer = StrWriterMut::from_custom_cleared(slice, &mut len);
57///     
58///     try_!(writec!(writer, "{0} in binary is {0:#b}", number));
59///
60///     Ok(len)
61/// }
62///
63/// let mut slice = [0; 32];
64///
65/// let len = format_number(100, &mut slice)?;
66///
67/// assert_eq!(&slice[..len], "100 in binary is 0b1100100".as_bytes());
68///
69/// # Ok::<(), const_format::Error>(())
70/// ```
71///
72/// [`from_custom_cleared`]: #method.from_custom_cleared
73/// [`from_custom`]: #method.from_custom
74///
75/// [`Utf8Encoding`]: crate::fmt::Utf8Encoding
76/// [`NoEncoding`]: crate::fmt::NoEncoding
77/// [`Formatter`]: crate::fmt::Formatter
78/// [`Error::NotEnoughSpace`]: crate::fmt::Error::NotEnoughSpace
79///
80pub struct StrWriterMut<'w, E = Utf8Encoding> {
81    pub(super) len: &'w mut usize,
82    pub(super) buffer: &'w mut [u8],
83    pub(super) _encoding: PhantomData<Constructor<E>>,
84}
85
86macro_rules! borrow_fields {
87    ($self:ident, $len:ident, $buffer:ident) => {
88        let $len = &mut *$self.len;
89        let $buffer = &mut *$self.buffer;
90    };
91}
92
93/// Marker type indicating that the [`StrWriterMut`] is valid utf8,
94/// enabling the `as_str` method.
95///
96/// [`StrWriterMut`]: ./struct.StrWriterMut.html
97pub enum Utf8Encoding {}
98
99/// Marker type indicating that the [`StrWriterMut`] is arbitrary bytes,
100/// disabling the `as_str` method.
101///
102/// [`StrWriterMut`]: ./struct.StrWriterMut.html
103pub enum NoEncoding {}
104
105impl<'w> StrWriterMut<'w, Utf8Encoding> {
106    /// Constructs a `StrWriterMut` from a mutable reference to a `StrWriter`
107    ///
108    /// # Example
109    ///
110    /// ```rust
111    /// use const_format::{StrWriter, StrWriterMut};
112    ///
113    /// let buffer: &mut StrWriter = &mut StrWriter::new([0; 128]);
114    /// {
115    ///     let mut writer = StrWriterMut::new(buffer);
116    ///
117    ///     let _ = writer.write_str("Number: ");
118    ///     let _ = writer.write_u8_display(1);
119    /// }
120    /// assert_eq!(buffer.as_str(), "Number: 1");
121    ///
122    /// ```
123    pub const fn new(writer: &'w mut StrWriter) -> Self {
124        Self {
125            len: &mut writer.len,
126            buffer: &mut writer.buffer,
127            _encoding: PhantomData,
128        }
129    }
130}
131
132impl<'w> StrWriterMut<'w, NoEncoding> {
133    /// Construct a `StrWriterMut` from length and byte slice mutable references.
134    ///
135    /// If `length > buffer.len()` is passed, it's simply assigned the length of the buffer.
136    ///
137    /// # Example
138    ///
139    /// ```rust
140    /// use const_format::StrWriterMut;
141    ///
142    /// let mut len = 6;
143    /// let mut buffer = *b"Hello,       ";
144    ///
145    /// let mut writer = StrWriterMut::from_custom(&mut buffer, &mut len);
146    ///
147    /// writer.write_str(" world!")?;
148    ///
149    /// assert_eq!(writer.as_bytes(), b"Hello, world!");
150    /// assert_eq!(buffer, "Hello, world!".as_bytes());
151    /// assert_eq!(len, "Hello, world!".len());
152    ///
153    /// # Ok::<(), const_format::Error>(())
154    /// ```
155    pub const fn from_custom(buffer: &'w mut [u8], length: &'w mut usize) -> Self {
156        *length = min_usize(*length, buffer.len());
157
158        Self {
159            len: length,
160            buffer,
161            _encoding: PhantomData,
162        }
163    }
164}
165
166impl<'w> StrWriterMut<'w, Utf8Encoding> {
167    /// Construct a `StrWriterMut` from length and byte slice mutable references,
168    /// truncating the length to `0`.
169    ///
170    /// Using this instead of [`from_custom`](StrWriterMut::from_custom) allows
171    /// safely casting this to a `&str` with [`as_str`]
172    ///
173    ///
174    /// # Example
175    ///
176    /// ```rust
177    /// use const_format::StrWriterMut;
178    ///
179    /// let mut len = 0;
180    /// let mut buffer = [0; 13];
181    ///
182    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
183    ///
184    /// writer.write_str("Hello, world!")?;
185    ///
186    /// assert_eq!(writer.as_str(), "Hello, world!");
187    /// assert_eq!(buffer, "Hello, world!".as_bytes());
188    /// assert_eq!(len, "Hello, world!".len());
189    ///
190    /// # Ok::<(), const_format::Error>(())
191    /// ```
192    ///
193    /// [`as_str`]: Self::as_str
194    ///
195    pub const fn from_custom_cleared(buffer: &'w mut [u8], length: &'w mut usize) -> Self {
196        *length = 0;
197
198        Self {
199            len: length,
200            buffer,
201            _encoding: PhantomData,
202        }
203    }
204}
205
206impl<'w, E> StrWriterMut<'w, E> {
207    /// Accesses the underlying buffer immutably.
208    ///
209    /// # Example
210    ///
211    /// ```rust
212    /// use const_format::{StrWriter, StrWriterMut};
213    ///
214    /// let mut buffer = StrWriter::new([0; 7]);
215    /// let mut writer = StrWriterMut::new(&mut buffer);
216    /// assert_eq!(writer.buffer(), &[0; 7]);
217    ///
218    /// writer.write_str("foo")?;
219    /// assert_eq!(writer.buffer(), b"foo\0\0\0\0");
220    ///
221    /// writer.write_str("bar")?;
222    /// assert_eq!(writer.buffer(), b"foobar\0");
223    ///
224    /// # Ok::<(), const_format::Error>(())
225    /// ```
226    #[inline(always)]
227    pub const fn buffer(&self) -> &[u8] {
228        self.buffer
229    }
230
231    /// The byte length of the string this is writing.
232    ///
233    /// # Example
234    ///
235    /// ```rust
236    /// use const_format::{StrWriter, StrWriterMut};
237    ///
238    /// let mut buffer = StrWriter::new([0; 64]);
239    /// let mut writer = StrWriterMut::new(&mut buffer);
240    ///
241    /// assert_eq!(writer.len(), 0);
242    ///
243    /// writer.write_str("foo")?;
244    /// assert_eq!(writer.len(), 3);
245    ///
246    /// writer.write_str("bar")?;
247    /// assert_eq!(writer.len(), 6);
248    ///
249    /// # Ok::<(), const_format::Error>(())
250    /// ```
251    #[inline(always)]
252    pub const fn len(&self) -> usize {
253        *self.len
254    }
255
256    /// Whether the string this is writing is empty.
257    ///
258    /// # Example
259    ///
260    /// ```rust
261    /// use const_format::{StrWriter, StrWriterMut};
262    ///
263    /// let mut buffer = StrWriter::new([0; 64]);
264    /// let mut writer = StrWriterMut::new(&mut buffer);
265    ///
266    /// assert!( writer.is_empty() );
267    ///
268    /// writer.write_str("foo")?;
269    /// assert!( !writer.is_empty() );
270    ///
271    /// # Ok::<(), const_format::Error>(())
272    /// ```
273    #[inline(always)]
274    pub const fn is_empty(&self) -> bool {
275        *self.len == 0
276    }
277
278    /// The maximum byte length of the formatted text for this `StrWriterMut`.
279    ///
280    /// # Example
281    ///
282    /// ```rust
283    /// use const_format::{Error, StrWriter, StrWriterMut};
284    ///
285    /// let mut buffer = StrWriter::new([0; 64]);
286    /// let mut writer = StrWriterMut::new(&mut buffer);
287    ///
288    /// assert_eq!(writer.capacity(), 64);
289    ///
290    /// writer.write_ascii_repeated(b'A', 64)?;
291    /// assert_eq!(writer.capacity(), 64);
292    ///
293    /// assert_eq!(writer.write_str("-").unwrap_err(), Error::NotEnoughSpace);
294    /// assert_eq!(writer.capacity(), 64);
295    ///
296    /// # Ok::<(), const_format::Error>(())
297    /// ```
298    #[inline(always)]
299    pub const fn capacity(&self) -> usize {
300        self.buffer.len()
301    }
302
303    /// Checks how many more bytes can be written.
304    ///
305    /// # Example
306    ///
307    /// ```rust
308    /// use const_format::{Error, StrWriter, StrWriterMut};
309    ///
310    /// let mut buffer = StrWriter::new([0; 64]);
311    /// let mut writer = StrWriterMut::new(&mut buffer);
312    ///
313    /// assert_eq!(writer.remaining_capacity(), 64);
314    ///
315    /// writer.write_str("foo")?;
316    /// assert_eq!(writer.remaining_capacity(), 61);
317    ///
318    /// writer.write_ascii_repeated(b'a', 61)?;
319    /// assert_eq!(writer.remaining_capacity(), 0);
320    ///
321    /// assert_eq!(writer.write_str(" ").unwrap_err(), Error::NotEnoughSpace);
322    ///
323    /// # Ok::<(), const_format::Error>(())
324    /// ```
325    #[inline]
326    pub const fn remaining_capacity(&self) -> usize {
327        self.buffer.len() - *self.len
328    }
329}
330
331impl<'w> StrWriterMut<'w, Utf8Encoding> {
332    /// Truncates this `StrWriterMut` to `length`.
333    ///
334    /// If `length` is greater than the current length, this does nothing.
335    ///
336    /// # Errors
337    ///
338    /// Returns an `Error::NotOnCharBoundary` if `length` is not on a char boundary.
339    ///
340    /// # Example
341    ///
342    /// ```rust
343    /// use const_format::{Error, StrWriter, StrWriterMut};
344    ///
345    /// let mut buffer = StrWriter::new([0; 64]);
346    /// let mut writer = StrWriterMut::new(&mut buffer);
347    ///
348    /// writer.write_str("foo bâr baz");
349    /// assert_eq!(writer.as_str(), "foo bâr baz");
350    ///
351    /// assert_eq!(writer.truncate(6).unwrap_err(), Error::NotOnCharBoundary);
352    ///
353    /// writer.truncate(3)?;
354    /// assert_eq!(writer.as_str(), "foo");
355    ///
356    /// writer.write_str("ooooooo");
357    /// assert_eq!(writer.as_str(), "fooooooooo");
358    ///
359    /// # Ok::<(), const_format::Error>(())
360    /// ```
361    #[inline]
362    pub const fn truncate(&mut self, length: usize) -> Result<(), Error> {
363        if length <= *self.len {
364            if !is_valid_str_index(self.buffer, length) {
365                return Err(Error::NotOnCharBoundary);
366            }
367
368            *self.len = length;
369        }
370        Ok(())
371    }
372}
373
374impl<'w> StrWriterMut<'w, NoEncoding> {
375    /// Truncates this `StrWriterMut<'w, NoEncoding>` to `length`.
376    ///
377    /// If `length` is greater than the current length, this does nothing.
378    ///
379    /// # Example
380    ///
381    /// ```rust
382    /// use const_format::{Error, StrWriter, StrWriterMut};
383    ///
384    /// let mut buffer = [0; 32];
385    /// let mut len = 0;
386    /// let mut writer = StrWriterMut::from_custom(&mut buffer, &mut len);
387    ///
388    /// writer.write_str("foo bar baz");
389    /// assert_eq!(writer.as_bytes(), b"foo bar baz");
390    ///
391    /// // Truncating to anything larger than the length is a no-op.
392    /// writer.truncate(usize::MAX / 2);
393    /// assert_eq!(writer.as_bytes(), b"foo bar baz");
394    ///
395    /// writer.truncate(3);
396    /// assert_eq!(writer.as_bytes(), b"foo");
397    ///
398    /// writer.write_str("ooooooo");
399    /// assert_eq!(writer.as_bytes(), b"fooooooooo");
400    ///
401    /// ```
402    #[inline]
403    pub const fn truncate(&mut self, length: usize) {
404        if length < *self.len {
405            *self.len = length;
406        }
407    }
408}
409
410impl<'w, E> StrWriterMut<'w, E> {
411    /// Truncates this `StrWriterMut` to length 0.
412    ///
413    /// # Example
414    ///
415    /// ```rust
416    /// use const_format::{Error, StrWriter, StrWriterMut};
417    ///
418    /// let mut buffer = StrWriter::new([0; 64]);
419    /// let mut writer = StrWriterMut::new(&mut buffer);
420    ///
421    /// writer.write_str("foo")?;
422    /// assert_eq!(writer.as_str(), "foo");
423    ///
424    /// writer.clear();
425    /// assert_eq!(writer.as_str(), "");
426    /// assert!(writer.is_empty());
427    ///
428    /// writer.write_str("bar");
429    /// assert_eq!(writer.as_str(), "bar");
430    ///
431    /// # Ok::<(), const_format::Error>(())
432    /// ```
433    #[inline]
434    pub const fn clear(&mut self) {
435        *self.len = 0;
436    }
437
438    /// This is the same as `as_bytes`
439    ///
440    /// (this method only exists for backwards compatibility)
441    #[deprecated(since = "0.2.36", note = "redundant, same as `as_bytes`")]
442    #[inline(always)]
443    pub const fn as_bytes_alt(&self) -> &[u8] {
444        crate::utils::slice_up_to_len(self.buffer, *self.len)
445    }
446}
447
448impl<'w> StrWriterMut<'w, Utf8Encoding> {
449    /// This is the same as `as_str`
450    ///
451    /// (this method only exists for backwards compatibility)
452    #[deprecated(since = "0.2.36", note = "redundant, same as `as_str`")]
453    #[inline(always)]
454    pub const fn as_str_alt(&self) -> &str {
455        // All the methods that modify the buffer must ensure utf8 validity,
456        // only methods from this module need to ensure this.
457        unsafe { core::str::from_utf8_unchecked(self.as_bytes_alt()) }
458    }
459
460    /// Gets the written part of this StrWriterMut as a `&str`
461    ///
462    /// # Example
463    ///
464    /// ```rust
465    ///
466    /// use const_format::{StrWriter, StrWriterMut};
467    ///
468    /// let mut buffer = StrWriter::new([0; 64]);
469    /// let mut writer = StrWriterMut::new(&mut buffer);
470    ///
471    /// writer.write_str("Hello, how are you?");
472    ///
473    /// assert_eq!(writer.as_str(), "Hello, how are you?");
474    ///
475    /// ```
476    #[inline(always)]
477    pub const fn as_str(&self) -> &str {
478        // All the methods that modify the buffer must ensure utf8 validity,
479        // only methods from this module need to ensure this.
480        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
481    }
482}
483
484impl<'w, E> StrWriterMut<'w, E> {
485    /// Gets the written part of this `StrWriterMut` as a `&[u8]`
486    ///
487    /// The slice is guaranteed to be valid utf8, so this is mostly for convenience.
488    ///
489    /// # Example
490    ///
491    /// ```rust
492    ///
493    /// use const_format::{StrWriter, StrWriterMut};
494    ///
495    /// let mut buffer = StrWriter::new([0; 64]);
496    /// let mut writer = StrWriterMut::new(&mut buffer);
497    ///
498    /// writer.write_str("Hello, World!");
499    ///
500    /// assert_eq!(writer.as_bytes(), "Hello, World!".as_bytes());
501    ///
502    /// ```
503    #[inline(always)]
504    pub const fn as_bytes(&self) -> &[u8] {
505        crate::utils::slice_up_to_len(self.buffer, *self.len)
506    }
507}
508
509impl<'w, E> StrWriterMut<'w, E> {
510    /// Constructs a [`Formatter`] that writes into this `StrWriterMut`,
511    /// which can be passed to debug and display formatting methods.
512    ///
513    /// # Example
514    ///
515    /// ```rust
516    ///
517    /// use const_format::{Error, Formatter, FormattingFlags, StrWriter, StrWriterMut};
518    /// use const_format::call_debug_fmt;
519    ///
520    /// use std::ops::Range;
521    ///
522    /// const fn range_debug_fmt(
523    ///     slice: &[Range<usize>],
524    ///     f: &mut Formatter<'_>
525    /// ) -> Result<(), Error> {
526    ///     // We need this macro to debug format arrays of non-primitive types
527    ///     // Also, it implicitly returns a `const_format::Error` on error.
528    ///     call_debug_fmt!(array, slice, f);
529    ///     Ok(())
530    /// }
531    ///
532    /// let mut buffer = StrWriter::new([0; 64]);
533    /// let mut writer = StrWriterMut::new(&mut buffer);
534    ///
535    /// range_debug_fmt(
536    ///     &[0..14, 14..31, 31..48],
537    ///     &mut writer.make_formatter(FormattingFlags::new().set_binary())
538    /// )?;
539    ///    
540    /// assert_eq!(writer.as_str(), "[0..1110, 1110..11111, 11111..110000]");
541    ///
542    /// # Ok::<(), Error>(())
543    ///
544    /// ```
545    ///
546    /// [`Formatter`]: ./struct.Formatter.html
547    #[inline(always)]
548    pub const fn make_formatter(&mut self, flags: FormattingFlags) -> Formatter<'_> {
549        Formatter::from_sw_mut(
550            StrWriterMut::<NoEncoding> {
551                len: self.len,
552                buffer: self.buffer,
553                _encoding: PhantomData,
554            },
555            flags,
556        )
557    }
558
559    /// For borrowing this mutably in macros, without getting nested mutable references.
560    #[inline(always)]
561    pub const fn borrow_mutably(&mut self) -> &mut StrWriterMut<'w, E> {
562        self
563    }
564
565    /// For passing a reborrow of this `StrWriterMut` into functions,
566    /// without this you'd need to pass a mutable reference instead.
567    ///
568    /// # Example
569    ///
570    /// ```rust
571    ///
572    /// use const_format::{Error, FormattingFlags, StrWriter, StrWriterMut, call_debug_fmt};
573    ///
574    /// use std::ops::Range;
575    ///
576    /// const fn range_debug_fmt(
577    ///     slice: &[[u32; 2]],
578    ///     mut writer: StrWriterMut<'_>
579    /// ) -> Result<(), Error> {
580    ///     let mut formatter = writer.make_formatter(FormattingFlags::new().set_binary());
581    ///
582    ///     // We need this macro to debug format arrays of non-primitive types
583    ///     // Also, it implicitly returns a `const_format::Error` on error.
584    ///     call_debug_fmt!(array, slice, formatter);
585    ///     Ok(())
586    /// }
587    ///
588    /// let mut buffer = StrWriter::new([0; 64]);
589    /// let mut writer = StrWriterMut::new(&mut buffer);
590    ///
591    /// range_debug_fmt(&[[3, 5], [8, 13]], writer.reborrow())?;
592    ///    
593    /// assert_eq!(writer.as_str(), "[[11, 101], [1000, 1101]]");
594    ///
595    /// # Ok::<(), Error>(())
596    ///
597    /// ```
598    #[inline(always)]
599    pub const fn reborrow(&mut self) -> StrWriterMut<'_, E> {
600        StrWriterMut {
601            len: self.len,
602            buffer: self.buffer,
603            _encoding: PhantomData,
604        }
605    }
606
607    // Safety: You must not write invalid utf8 bytes with the returned StrWriterMut.
608    pub(crate) const unsafe fn into_byte_encoding(self) -> StrWriterMut<'w, NoEncoding> {
609        StrWriterMut {
610            len: self.len,
611            buffer: self.buffer,
612            _encoding: PhantomData,
613        }
614    }
615}
616
617/////////////////////////////////////////////////////////////////////////////////
618
619macro_rules! write_integer_fn {
620    (
621        display_attrs $display_attrs:tt
622        debug_attrs $debug_attrs:tt
623        $(($display_fn:ident, $debug_fn:ident, $sign:ident, $ty:ident, $Unsigned:ident))*
624    )=>{
625        impl<'w,E> StrWriterMut<'w,E>{
626            $(
627                write_integer_fn!{
628                    @methods
629                    display_attrs $display_attrs
630                    debug_attrs $debug_attrs
631                    $display_fn, $debug_fn, $sign, ($ty, $Unsigned), stringify!($ty)
632                }
633            )*
634        }
635
636        $(
637            write_integer_fn!{
638                @pwrapper
639                $display_fn, $debug_fn, $sign, ($ty, $Unsigned), stringify!($ty)
640            }
641        )*
642    };
643    (@pwrapper
644        $display_fn:ident,
645        $debug_fn:ident,
646        $sign:ident,
647        ($ty:ident, $Unsigned:ident),
648        $ty_name:expr
649    )=>{
650        impl PWrapper<$ty> {
651            /// Writes a
652            #[doc = $ty_name]
653            /// with Display formatting.
654            pub const fn const_display_fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
655                f.$display_fn(self.0)
656            }
657
658            /// Writes a
659            #[doc = $ty_name]
660            /// with Debug formatting.
661            pub const fn const_debug_fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
662                f.$debug_fn(self.0)
663            }
664        }
665    };
666    (@methods
667        display_attrs( $(#[$display_attrs:meta])* )
668        debug_attrs( $(#[$debug_attrs:meta])* )
669        $display_fn:ident,
670        $debug_fn:ident,
671        $sign:ident,
672        ($ty:ident, $Unsigned:ident),
673        $ty_name:expr
674    )=>{
675        $(#[$display_attrs])*
676        pub const fn $display_fn(&mut self, number: $ty) -> Result<(), Error> {
677            borrow_fields!(self, this_len, this_buffer);
678
679            let n = PWrapper(number);
680            let len = n.compute_display_len(FormattingFlags::DEFAULT);
681
682            let mut cursor = *this_len + len;
683
684            if cursor > this_buffer.len() {
685                return Err(Error::NotEnoughSpace);
686            }
687
688            write_integer_fn!(@unsigned_abs $sign, n);
689
690            loop {
691                cursor-=1;
692                let digit = (n % 10) as u8;
693                this_buffer[cursor] = b'0' + digit;
694                n/=10;
695                if n == 0 { break }
696            }
697
698            write_integer_fn!(@write_sign $sign, this_len, this_buffer, number);
699
700            *this_len+=len;
701            Ok(())
702        }
703
704        $(#[$debug_attrs])*
705        pub const fn $debug_fn(
706            &mut self,
707            number: $ty,
708            flags: FormattingFlags,
709        ) -> Result<(), Error> {
710            const fn hex<E>(
711                this: &mut StrWriterMut<'_, E>,
712                n: $ty,
713                f: FormattingFlags,
714            ) -> Result<(), Error> {
715                borrow_fields!(this, this_len, this_buffer);
716
717                let is_alternate = f.is_alternate();
718                let len = PWrapper(n).hexadecimal_len(f);
719
720                let mut cursor = *this_len + len;
721
722                if cursor > this_buffer.len() {
723                    return Err(Error::NotEnoughSpace);
724                }
725
726                if is_alternate {
727                    this_buffer[*this_len] = b'0';
728                    this_buffer[*this_len + 1] = b'x';
729                }
730
731                write_integer_fn!(@as_unsigned $sign, n, $Unsigned);
732
733                loop {
734                    cursor-=1;
735                    let digit = (n & 0b1111) as u8;
736                    this_buffer[cursor] = hex_as_ascii(digit, f.hex_fmt());
737                    n >>= 4;
738                    if n == 0 { break }
739                }
740
741                *this_len+=len;
742                Ok(())
743            }
744
745            const fn binary<E>(
746                this: &mut StrWriterMut<'_, E>,
747                n: $ty,
748                f: FormattingFlags,
749            ) -> Result<(), Error> {
750                borrow_fields!(this, this_len, this_buffer);
751
752                let is_alternate = f.is_alternate();
753                let len = PWrapper(n).binary_len(f);
754
755                let mut cursor = *this_len + len;
756
757                if cursor > this_buffer.len() {
758                    return Err(Error::NotEnoughSpace);
759                }
760
761                if is_alternate {
762                    this_buffer[*this_len] = b'0';
763                    this_buffer[*this_len + 1] = b'b';
764                }
765
766                write_integer_fn!(@as_unsigned $sign, n, $Unsigned);
767
768                loop {
769                    cursor-=1;
770                    let digit = (n & 1) as u8;
771                    this_buffer[cursor] = hex_as_ascii(digit, f.hex_fmt());
772                    n >>= 1;
773                    if n == 0 { break }
774                }
775
776                *this_len+=len;
777                Ok(())
778            }
779
780            match flags.num_fmt() {
781                NumberFormatting::Decimal=>self.$display_fn(number),
782                NumberFormatting::Hexadecimal=>hex(self, number, flags),
783                NumberFormatting::Binary=>binary(self, number, flags),
784            }
785        }
786    };
787    (@unsigned_abs signed, $n:ident) => (
788        let mut $n = $n.unsigned_abs();
789    );
790    (@unsigned_abs unsigned, $n:ident) => (
791        let mut $n = $n.0;
792    );
793    (@as_unsigned signed, $n:ident, $Unsigned:ident) => (
794        let mut $n = $n as $Unsigned;
795    );
796    (@as_unsigned unsigned, $n:ident, $Unsigned:ident) => (
797        let mut $n = $n;
798    );
799    (@write_sign signed, $self_len:ident, $self_buffer:ident, $n:ident) => ({
800        if $n < 0 {
801            $self_buffer[*$self_len] = b'-';
802        }
803    });
804    (@write_sign unsigned, $self_len:ident, $self_buffer:ident, $n:ident) => ({});
805}
806
807/// Checks that a range is valid for indexing a string,
808/// assuming that the range is in-bounds, and start <= end.
809#[inline]
810const fn is_valid_str_range(s: &[u8], Range { start, end }: Range<usize>) -> bool {
811    let len = s.len();
812
813    (end == len || ((s[end] as i8) >= -0x40)) && (start == len || ((s[start] as i8) >= -0x40))
814}
815
816/// Checks that an index is valid for indexing a string,
817/// assuming that the index is in-bounds.
818#[inline]
819const fn is_valid_str_index(s: &[u8], index: usize) -> bool {
820    let len = s.len();
821
822    index == len || ((s[index] as i8) >= -0x40)
823}
824
825impl<'w, E> StrWriterMut<'w, E> {
826    /// Writes a subslice of `s` with Display formatting.
827    ///
828    /// This is a workaround for being unable to do `&foo[start..end]` at compile time.
829    ///
830    /// # Additional Errors
831    ///
832    /// This method returns `Error::NotOnCharBoundary` if the range is not
833    /// on a character boundary.
834    ///
835    /// Out of bounds range bounds are treated as being at `s.len()`,
836    /// this only returns an error on an in-bounds index that is not on a character boundary.
837    ///
838    /// # Example
839    ///
840    /// ```rust
841    /// use const_format::{FormattingFlags, StrWriterMut};
842    ///
843    /// let mut len = 0;
844    /// let mut buffer = [0; 64];
845    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
846    ///
847    /// let _ = writer.write_str_range("FOO BAR BAZ", 4..7);
848    ///
849    /// assert_eq!(writer.as_str(), "BAR");
850    ///
851    /// ```
852    ///
853    pub const fn write_str_range(&mut self, s: &str, range: Range<usize>) -> Result<(), Error> {
854        let bytes = s.as_bytes();
855        let Range { start, end } = saturate_range(bytes, &range);
856
857        if !is_valid_str_range(bytes, start..end) {
858            return Err(Error::NotOnCharBoundary);
859        }
860
861        self.write_str_inner(bytes, start, end)
862    }
863
864    /// Writes `s` with Display formatting.
865    ///
866    /// # Example
867    ///
868    /// ```rust
869    ///
870    /// use const_format::{FormattingFlags, StrWriterMut};
871    ///
872    /// let mut len = 0;
873    /// let mut buffer = [0; 64];
874    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
875    ///
876    /// let _ = writer.write_str("FOO BAR BAZ");
877    ///
878    /// assert_eq!(writer.as_str(), "FOO BAR BAZ");
879    ///
880    /// ```
881    ///
882    pub const fn write_str(&mut self, s: &str) -> Result<(), Error> {
883        let bytes = s.as_bytes();
884
885        self.write_str_inner(bytes, 0, s.len())
886    }
887
888    /// Writes `character` with Display formatting
889    ///
890    /// # Example
891    ///
892    /// ```rust
893    ///
894    /// use const_format::StrWriterMut;
895    ///
896    /// let mut len = 0;
897    /// let mut buffer = [0; 64];
898    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
899    ///
900    /// let _ = writer.write_char('3');
901    /// let _ = writer.write_char('5');
902    /// let _ = writer.write_char('8');
903    ///
904    /// assert_eq!(writer.as_str(), "358");
905    ///
906    /// ```
907    ///
908    pub const fn write_char(&mut self, character: char) -> Result<(), Error> {
909        let fmt = crate::char_encoding::char_to_display(character);
910        self.write_str_inner(fmt.encoded(), 0, fmt.len())
911    }
912
913    /// Writes a subslice of `ascii` with Display formatting.
914    ///
915    /// Out of bounds range bounds are treated as being at `s.len()`.
916    ///
917    /// This is a workaround for being unable to do `&foo[start..end]` at compile time.
918    ///
919    /// # Example
920    ///
921    /// ```rust
922    ///
923    /// use const_format::{FormattingFlags, StrWriterMut, ascii_str};
924    ///
925    /// let mut len = 0;
926    /// let mut buffer = [0; 64];
927    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
928    ///
929    /// let _ = writer.write_ascii_range(ascii_str!("FOO BAR BAZ"), 4..7);
930    ///
931    /// assert_eq!(writer.as_str(), "BAR");
932    ///
933    /// ```
934    ///
935    pub const fn write_ascii_range(
936        &mut self,
937        ascii: AsciiStr<'_>,
938        range: Range<usize>,
939    ) -> Result<(), Error> {
940        let bytes = ascii.as_bytes();
941        let Range { start, end } = saturate_range(bytes, &range);
942
943        self.write_str_inner(bytes, start, end)
944    }
945
946    /// Writes `ascii` with Display formatting.
947    ///
948    /// # Example
949    ///
950    /// ```rust
951    ///
952    /// use const_format::{FormattingFlags, StrWriterMut, ascii_str};
953    ///
954    /// let mut len = 0;
955    /// let mut buffer = [0; 64];
956    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
957    ///
958    /// let _ = writer.write_ascii(ascii_str!("FOO BAR BAZ"));
959    ///
960    /// assert_eq!(writer.as_str(), "FOO BAR BAZ");
961    ///
962    /// ```
963    ///
964    pub const fn write_ascii(&mut self, ascii: AsciiStr<'_>) -> Result<(), Error> {
965        let bytes = ascii.as_bytes();
966
967        self.write_str_inner(bytes, 0, bytes.len())
968    }
969
970    /// Writes an ascii `character`, `repeated` times.
971    ///
972    /// # Example
973    ///
974    /// ```rust
975    ///
976    /// use const_format::{FormattingFlags, StrWriterMut};
977    ///
978    /// let mut len = 0;
979    /// let mut buffer = [0; 64];
980    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
981    ///
982    /// let _ = writer.write_ascii_repeated(b'A', 10);
983    ///
984    /// assert_eq!(writer.as_str(), "AAAAAAAAAA");
985    ///
986    /// ```
987    ///
988    pub const fn write_ascii_repeated(
989        &mut self,
990        mut character: u8,
991        repeated: usize,
992    ) -> Result<(), Error> {
993        borrow_fields!(self, self_len, self_buffer);
994
995        // Truncating non-ascii u8s
996        character &= 0b111_1111;
997
998        let end = *self_len + repeated;
999
1000        if end > self_buffer.len() {
1001            return Err(Error::NotEnoughSpace);
1002        }
1003
1004        while *self_len < end {
1005            self_buffer[*self_len] = character;
1006            *self_len += 1;
1007        }
1008
1009        Ok(())
1010    }
1011
1012    #[inline(always)]
1013    const fn write_str_inner(
1014        &mut self,
1015        bytes: &[u8],
1016        mut start: usize,
1017        end: usize,
1018    ) -> Result<(), Error> {
1019        borrow_fields!(self, self_len, self_buffer);
1020
1021        let len = end - start;
1022
1023        if *self_len + len > self_buffer.len() {
1024            return Err(Error::NotEnoughSpace);
1025        }
1026
1027        while start < end {
1028            self_buffer[*self_len] = bytes[start];
1029            *self_len += 1;
1030            start += 1;
1031        }
1032
1033        Ok(())
1034    }
1035}
1036
1037/// Debug-formatted string writing
1038impl<'w, E> StrWriterMut<'w, E> {
1039    /// Writes a subslice of `s` with  Debug-like formatting.
1040    ///
1041    /// This is a workaround for being unable to do `&foo[start..end]` at compile time.
1042    ///
1043    /// # Additional Errors
1044    ///
1045    /// This method returns `Error::NotOnCharBoundary` if the range is not
1046    /// on a character boundary.
1047    ///
1048    /// Out of bounds range bounds are treated as being at `s.len()`,
1049    /// this only returns an error on an in-bounds index that is not on a character boundary.
1050    ///
1051    /// # Example
1052    ///
1053    /// ```rust
1054    ///
1055    /// use const_format::{FormattingFlags, StrWriterMut};
1056    ///
1057    /// let mut len = 0;
1058    /// let mut buffer = [0; 64];
1059    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
1060    ///
1061    /// let _ = writer.write_str_range_debug("FOO\nBAR\tBAZ", 3..8);
1062    ///
1063    /// assert_eq!(writer.as_str(), r#""\nBAR\t""#);
1064    ///
1065    /// ```
1066    ///
1067    pub const fn write_str_range_debug(
1068        &mut self,
1069        s: &str,
1070        range: Range<usize>,
1071    ) -> Result<(), Error> {
1072        let bytes = s.as_bytes();
1073        let Range { start, end } = saturate_range(bytes, &range);
1074
1075        if !is_valid_str_range(bytes, start..end) {
1076            return Err(Error::NotOnCharBoundary);
1077        }
1078
1079        self.write_str_debug_inner(bytes, start, end)
1080    }
1081
1082    /// Writes `s` with Debug-like formatting.
1083    ///
1084    /// # Example
1085    ///
1086    /// ```rust
1087    ///
1088    /// use const_format::{FormattingFlags, StrWriterMut};
1089    ///
1090    /// let mut len = 0;
1091    /// let mut buffer = [0; 64];
1092    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
1093    ///
1094    /// let _ = writer.write_str_debug("FOO\nBAR\tBAZ");
1095    ///
1096    /// assert_eq!(writer.as_str(), r#""FOO\nBAR\tBAZ""#);
1097    ///
1098    /// ```
1099    ///
1100    pub const fn write_str_debug(&mut self, str: &str) -> Result<(), Error> {
1101        let bytes = str.as_bytes();
1102        self.write_str_debug_inner(bytes, 0, str.len())
1103    }
1104
1105    /// Writes `character` with Debug formatting.
1106    ///
1107    /// # Example
1108    ///
1109    /// ```rust
1110    ///
1111    /// use const_format::StrWriterMut;
1112    ///
1113    /// let mut len = 0;
1114    /// let mut buffer = [0; 64];
1115    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
1116    ///
1117    /// let _ = writer.write_str(" ");
1118    /// let _ = writer.write_char_debug('\\');
1119    /// let _ = writer.write_str(" ");
1120    /// let _ = writer.write_char_debug('A');
1121    /// let _ = writer.write_str(" ");
1122    /// let _ = writer.write_char_debug('0');
1123    /// let _ = writer.write_str(" ");
1124    /// let _ = writer.write_char_debug('\'');
1125    /// let _ = writer.write_str(" ");
1126    ///
1127    /// assert_eq!(writer.as_str(), r#" '\\' 'A' '0' '\'' "#);
1128    ///
1129    /// ```
1130    ///
1131    pub const fn write_char_debug(&mut self, character: char) -> Result<(), Error> {
1132        let fmt = crate::char_encoding::char_to_debug(character);
1133        self.write_str_inner(fmt.encoded(), 0, fmt.len())
1134    }
1135
1136    /// Writes a subslice of `ascii` with Debug-like formatting.
1137    ///
1138    /// Out of bounds range bounds are treated as being at `s.len()`.
1139    ///
1140    /// This is a workaround for being unable to do `&foo[start..end]` at compile time.
1141    ///
1142    /// # Example
1143    ///
1144    /// ```rust
1145    ///
1146    /// use const_format::{FormattingFlags, StrWriterMut, ascii_str};
1147    ///
1148    /// let mut len = 0;
1149    /// let mut buffer = [0; 64];
1150    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
1151    ///
1152    /// let _ = writer.write_ascii_range_debug(ascii_str!("FOO\nBAR\tBAZ"), 3..8);
1153    ///
1154    /// assert_eq!(writer.as_str(), r#""\nBAR\t""#);
1155    ///
1156    /// ```
1157    ///
1158    pub const fn write_ascii_range_debug(
1159        &mut self,
1160        ascii: AsciiStr<'_>,
1161        range: Range<usize>,
1162    ) -> Result<(), Error> {
1163        let bytes = ascii.as_bytes();
1164        let Range { start, end } = saturate_range(bytes, &range);
1165
1166        self.write_str_debug_inner(bytes, start, end)
1167    }
1168
1169    /// Writes `ascii` with Debug-like formatting.
1170    ///
1171    /// # Example
1172    ///
1173    /// ```rust
1174    ///
1175    /// use const_format::{FormattingFlags, StrWriterMut, ascii_str};
1176    ///
1177    /// let mut len = 0;
1178    /// let mut buffer = [0; 64];
1179    /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
1180    ///
1181    /// let _ = writer.write_ascii_debug(ascii_str!("FOO\nBAR\tBAZ"));
1182    ///
1183    /// assert_eq!(writer.as_str(), r#""FOO\nBAR\tBAZ""#);
1184    ///
1185    /// ```
1186    ///
1187    pub const fn write_ascii_debug(&mut self, ascii: AsciiStr<'_>) -> Result<(), Error> {
1188        let bytes = ascii.as_bytes();
1189        self.write_str_debug_inner(bytes, 0, bytes.len())
1190    }
1191
1192    #[inline(always)]
1193    const fn write_str_debug_inner(
1194        &mut self,
1195        bytes: &[u8],
1196        mut start: usize,
1197        end: usize,
1198    ) -> Result<(), Error> {
1199        borrow_fields!(self, self_len, self_buffer);
1200
1201        let len = end - start;
1202
1203        // + 2 for the quote characters around the string.
1204        if *self_len + len + 2 > self_buffer.len() {
1205            return Err(Error::NotEnoughSpace);
1206        }
1207
1208        // The amount of bytes available for escapes,
1209        // not counting the `writte_c`.
1210        let mut remaining_for_escapes = (self_buffer.len() - 2 - len - *self_len) as isize;
1211        let mut written = *self_len;
1212
1213        self_buffer[written] = b'"';
1214        written += 1;
1215
1216        while start != end {
1217            let c = bytes[start];
1218            let mut written_c = c;
1219
1220            let shifted;
1221
1222            if c < 128
1223                && ({
1224                    shifted = 1 << c;
1225                    (FOR_ESCAPING.is_escaped & shifted) != 0
1226                })
1227            {
1228                self_buffer[written] = b'\\';
1229                written += 1;
1230
1231                if (FOR_ESCAPING.is_backslash_escaped & shifted) != 0 {
1232                    remaining_for_escapes -= 1;
1233                    if remaining_for_escapes < 0 {
1234                        return Err(Error::NotEnoughSpace);
1235                    }
1236                    written_c = ForEscaping::get_backslash_escape(c);
1237                } else {
1238                    remaining_for_escapes -= 3;
1239                    if remaining_for_escapes < 0 {
1240                        return Err(Error::NotEnoughSpace);
1241                    }
1242                    self_buffer[written] = b'x';
1243                    written += 1;
1244                    self_buffer[written] = hex_as_ascii(c >> 4, HexFormatting::Upper);
1245                    written += 1;
1246                    written_c = hex_as_ascii(c & 0xF, HexFormatting::Upper);
1247                };
1248            }
1249
1250            self_buffer[written] = written_c;
1251            written += 1;
1252            start += 1;
1253        }
1254
1255        self_buffer[written] = b'"';
1256        written += 1;
1257
1258        *self_len = written;
1259
1260        Ok(())
1261    }
1262}
1263
1264write_integer_fn! {
1265    display_attrs(
1266        /// Write `number` with display formatting.
1267        ///
1268        /// # Example
1269        ///
1270        /// ```rust
1271        ///
1272        /// use const_format::{Formatter, FormattingFlags, StrWriterMut, ascii_str};
1273        ///
1274        /// let mut len = 0;
1275        /// let mut buffer = [0; 64];
1276        /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
1277        ///
1278        /// let _ = writer.write_u8_display(137);
1279        ///
1280        /// assert_eq!(writer.as_str(), "137");
1281        ///
1282        /// ```
1283        ///
1284    )
1285    debug_attrs(
1286        /// Writes `number` with debug formatting.
1287        ///
1288        /// # Example
1289        ///
1290        /// ```rust
1291        ///
1292        /// use const_format::{FormattingFlags, StrWriterMut};
1293        ///
1294        /// const fn debug_fmt<'a>(
1295        ///     writer: &'a mut StrWriterMut<'_>,
1296        ///     flag: FormattingFlags
1297        /// ) -> &'a str {
1298        ///     writer.clear();
1299        ///     let _ = writer.write_u8_debug(63, flag);
1300        ///     writer.as_str()
1301        /// }
1302        ///
1303        /// let reg_flag = FormattingFlags::NEW.set_alternate(false);
1304        /// let alt_flag = FormattingFlags::NEW.set_alternate(true);
1305        ///
1306        /// let mut len = 0;
1307        /// let mut buffer = [0; 64];
1308        /// let mut writer = StrWriterMut::from_custom_cleared(&mut buffer, &mut len);
1309        ///
1310        /// assert_eq!(debug_fmt(&mut writer, reg_flag),                   "63"     );
1311        /// assert_eq!(debug_fmt(&mut writer, reg_flag.set_hexadecimal()), "3F"     );
1312        /// assert_eq!(debug_fmt(&mut writer, reg_flag.set_lower_hexadecimal()), "3f");
1313        /// assert_eq!(debug_fmt(&mut writer, reg_flag.set_binary()),      "111111" );
1314        /// assert_eq!(debug_fmt(&mut writer, alt_flag),                   "63"     );
1315        /// assert_eq!(debug_fmt(&mut writer, alt_flag.set_hexadecimal()), "0x3F"   );
1316        /// assert_eq!(debug_fmt(&mut writer, alt_flag.set_lower_hexadecimal()), "0x3f");
1317        /// assert_eq!(debug_fmt(&mut writer, alt_flag.set_binary()),      "0b111111");
1318        ///
1319        /// ```
1320        ///
1321    )
1322    (write_u8_display, write_u8_debug, unsigned, u8, u8)
1323}
1324write_integer_fn! {
1325    display_attrs(
1326        /// Writes `number` with display formatting
1327        ///
1328        /// For an example,
1329        /// you can look at the one for the [`write_u8_display`] method.
1330        ///
1331        /// [`write_u8_display`]: #method.write_u8_display
1332    )
1333    debug_attrs(
1334        /// Writes `number` with debug formatting.
1335        ///
1336        /// For an example,
1337        /// you can look at the one for the [`write_u8_debug`] method.
1338        ///
1339        /// [`write_u8_debug`]: #method.write_u8_debug
1340    )
1341    (write_u16_display, write_u16_debug, unsigned, u16, u16)
1342    (write_u32_display, write_u32_debug, unsigned, u32, u32)
1343    (write_u64_display, write_u64_debug, unsigned, u64, u64)
1344    (write_u128_display, write_u128_debug, unsigned, u128, u128)
1345    (write_usize_display, write_usize_debug, unsigned, usize, usize)
1346
1347    (write_i8_display, write_i8_debug, signed, i8, u8)
1348    (write_i16_display, write_i16_debug, signed, i16, u16)
1349    (write_i32_display, write_i32_debug, signed, i32, u32)
1350    (write_i64_display, write_i64_debug, signed, i64, u64)
1351    (write_i128_display, write_i128_debug, signed, i128, u128)
1352    (write_isize_display, write_isize_debug, signed, isize, usize)
1353}