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}