str.rs 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. // SPDX-License-Identifier: GPL-2.0
  2. //! String representations.
  3. use core::fmt;
  4. /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
  5. ///
  6. /// It does not fail if callers write past the end of the buffer so that they can calculate the
  7. /// size required to fit everything.
  8. ///
  9. /// # Invariants
  10. ///
  11. /// The memory region between `pos` (inclusive) and `end` (exclusive) is valid for writes if `pos`
  12. /// is less than `end`.
  13. pub(crate) struct RawFormatter {
  14. // Use `usize` to use `saturating_*` functions.
  15. #[allow(dead_code)]
  16. beg: usize,
  17. pos: usize,
  18. end: usize,
  19. }
  20. impl RawFormatter {
  21. /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
  22. ///
  23. /// # Safety
  24. ///
  25. /// If `pos` is less than `end`, then the region between `pos` (inclusive) and `end`
  26. /// (exclusive) must be valid for writes for the lifetime of the returned [`RawFormatter`].
  27. pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
  28. // INVARIANT: The safety requirements guarantee the type invariants.
  29. Self {
  30. beg: pos as _,
  31. pos: pos as _,
  32. end: end as _,
  33. }
  34. }
  35. /// Returns the current insert position.
  36. ///
  37. /// N.B. It may point to invalid memory.
  38. pub(crate) fn pos(&self) -> *mut u8 {
  39. self.pos as _
  40. }
  41. }
  42. impl fmt::Write for RawFormatter {
  43. fn write_str(&mut self, s: &str) -> fmt::Result {
  44. // `pos` value after writing `len` bytes. This does not have to be bounded by `end`, but we
  45. // don't want it to wrap around to 0.
  46. let pos_new = self.pos.saturating_add(s.len());
  47. // Amount that we can copy. `saturating_sub` ensures we get 0 if `pos` goes past `end`.
  48. let len_to_copy = core::cmp::min(pos_new, self.end).saturating_sub(self.pos);
  49. if len_to_copy > 0 {
  50. // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
  51. // yet, so it is valid for write per the type invariants.
  52. unsafe {
  53. core::ptr::copy_nonoverlapping(
  54. s.as_bytes().as_ptr(),
  55. self.pos as *mut u8,
  56. len_to_copy,
  57. )
  58. };
  59. }
  60. self.pos = pos_new;
  61. Ok(())
  62. }
  63. }