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}