@@ -374,28 +374,129 @@ mod tests {
374
374
}
375
375
}
376
376
377
- // Use `usize` to use `saturating_*` functions.
378
- pub ( crate ) struct Formatter {
379
- pub ( crate ) buf : usize ,
380
- pub ( crate ) end : usize ,
377
+ /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
378
+ ///
379
+ /// It does not fail if callers write past the end of the buffer so that they can calculate the
380
+ /// size required to fit everything.
381
+ ///
382
+ /// # Invariants
383
+ ///
384
+ /// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos`
385
+ /// is less than `end`.
386
+ pub ( crate ) struct RawFormatter {
387
+ // Use `usize` to use `saturating_*` functions.
388
+ beg : usize ,
389
+ pos : usize ,
390
+ end : usize ,
381
391
}
382
392
383
- impl fmt:: Write for Formatter {
393
+ impl RawFormatter {
394
+ /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
395
+ ///
396
+ /// # Safety
397
+ ///
398
+ /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end`
399
+ /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`].
400
+ pub ( crate ) unsafe fn from_ptrs ( pos : * mut u8 , end : * mut u8 ) -> Self {
401
+ // INVARIANT: The safety requierments guarantee the type invariants.
402
+ Self {
403
+ beg : pos as _ ,
404
+ pos : pos as _ ,
405
+ end : end as _ ,
406
+ }
407
+ }
408
+
409
+ /// Creates a new instance of [`RawFormatter`] with the given buffer.
410
+ ///
411
+ /// # Safety
412
+ ///
413
+ /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
414
+ /// for the lifetime of the returned [`RawFormatter`].
415
+ pub ( crate ) unsafe fn from_buffer ( buf : * mut u8 , len : usize ) -> Self {
416
+ let pos = buf as usize ;
417
+ // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements
418
+ // guarantees that the memory region is valid for writes.
419
+ Self {
420
+ pos,
421
+ beg : pos,
422
+ end : pos. saturating_add ( len) ,
423
+ }
424
+ }
425
+
426
+ /// Returns the current insert position.
427
+ ///
428
+ /// N.B. It may point to invalid memory.
429
+ pub ( crate ) fn pos ( & self ) -> * mut u8 {
430
+ self . pos as _
431
+ }
432
+
433
+ /// Return the number of bytes written to the formatter.
434
+ pub ( crate ) fn bytes_written ( & self ) -> usize {
435
+ self . pos - self . beg
436
+ }
437
+ }
438
+
439
+ impl fmt:: Write for RawFormatter {
384
440
fn write_str ( & mut self , s : & str ) -> fmt:: Result {
385
- // `buf ` value after writing `len` bytes. This does not have to be bounded by `end`, but we
441
+ // `pos ` value after writing `len` bytes. This does not have to be bounded by `end`, but we
386
442
// don't want it to wrap around to 0.
387
- let buf_new = self . buf . saturating_add ( s. len ( ) ) ;
443
+ let pos_new = self . pos . saturating_add ( s. len ( ) ) ;
444
+
445
+ // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`.
446
+ let len_to_copy = core:: cmp:: min ( pos_new, self . end ) . saturating_sub ( self . pos ) ;
447
+
448
+ if len_to_copy > 0 {
449
+ // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
450
+ // yet, so it is valid for write per the type invariants.
451
+ unsafe {
452
+ core:: ptr:: copy_nonoverlapping (
453
+ s. as_bytes ( ) . as_ptr ( ) ,
454
+ self . pos as * mut u8 ,
455
+ len_to_copy,
456
+ )
457
+ } ;
458
+ }
388
459
389
- // Amount that we can copy. `saturating_sub` ensures we get 0 if `buf` goes past `end`.
390
- let len_to_copy = core:: cmp:: min ( buf_new, self . end ) . saturating_sub ( self . buf ) ;
460
+ self . pos = pos_new;
461
+ Ok ( ( ) )
462
+ }
463
+ }
391
464
392
- // SAFETY: In any case, `buf` is non-null and properly aligned. If `len_to_copy` is
393
- // non-zero, then we know `buf` has not past `end` yet and so is valid.
394
- unsafe {
395
- core:: ptr:: copy_nonoverlapping ( s. as_bytes ( ) . as_ptr ( ) , self . buf as * mut u8 , len_to_copy)
396
- } ;
465
+ /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
466
+ ///
467
+ /// Fails if callers attempt to write more than will fit in the buffer.
468
+ pub ( crate ) struct Formatter ( RawFormatter ) ;
397
469
398
- self . buf = buf_new;
399
- Ok ( ( ) )
470
+ impl Formatter {
471
+ /// Creates a new instance of [`Formatter`] with the given buffer.
472
+ ///
473
+ /// # Safety
474
+ ///
475
+ /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
476
+ /// for the lifetime of the returned [`Formatter`].
477
+ pub ( crate ) unsafe fn from_buffer ( buf : * mut u8 , len : usize ) -> Self {
478
+ // SAFETY: The safety requirements of this function satisfy those of the callee.
479
+ Self ( unsafe { RawFormatter :: from_buffer ( buf, len) } )
480
+ }
481
+ }
482
+
483
+ impl Deref for Formatter {
484
+ type Target = RawFormatter ;
485
+
486
+ fn deref ( & self ) -> & Self :: Target {
487
+ & self . 0
488
+ }
489
+ }
490
+
491
+ impl fmt:: Write for Formatter {
492
+ fn write_str ( & mut self , s : & str ) -> fmt:: Result {
493
+ self . 0 . write_str ( s) ?;
494
+
495
+ // Fail the request if we go past the end of the buffer.
496
+ if self . 0 . pos > self . 0 . end {
497
+ Err ( fmt:: Error )
498
+ } else {
499
+ Ok ( ( ) )
500
+ }
400
501
}
401
502
}
0 commit comments