@@ -374,28 +374,129 @@ mod tests {
374374 }
375375}
376376
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 ,
381391}
382392
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 {
384440 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
386442 // 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+ }
388459
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+ }
391464
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 ) ;
397469
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+ }
400501 }
401502}
0 commit comments