1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use core::{
  fmt::Debug,
  marker::PhantomData,
  ops::{Deref, DerefMut},
  slice, str,
};

use super::StableLayout;

// General Safety Note: The soundness of the `UniqueStr` type is centered
// around the fact that the fields are all private, and so *safe rust* must
// construct values of the type from an existing valid slice. However, because
// the type is `repr(C)` it can of course be constructed with unsafe rust, or
// even by foreign code. It is the responsibility of _the other code_ to ensure
// that the actual fields are valid for being turned into a slice.

/// A struct for **unique** `str` views with a stable layout.
///
/// This is a `repr(C)` variant of `&mut str`. If you want a variant of `&str`
/// then you should use [`UniqueStr`](crate::UniqueStr) instead.
///
/// Rationale for using this type is given in the crate level docs.
///
/// ## Unsafety
///
/// Because this type is primarily intended to help _unsafe_ Rust we should
/// discuss the precise guarantees offered:
/// * **Validity Invariants**
///   * The data layout is a `*mut u8` and then a `usize`.
/// * **Soundness Invariants**
///   * The `*mut u8` must point to the start of a valid `&mut str`.
///   * The `usize` must be the correct length of that valid `&mut str`.
///   * For as long as the `UniqueStr` exists the memory in question has a
///     unique borrow over it (tracked via `PhantomData`).
///   * The memory must contain value UTF-8 data.
///
/// This type matches up with the following C layout:
/// ```c
/// #include <stdint.h>
/// // Identical layout to `UniqueStr<'a>`
/// typedef struct {
///   uint8_t *ptr;
///   uintptr_t len;
/// } UniqueStr;
/// ```
#[repr(C)]
pub struct UniqueStr<'a> {
  ptr: *mut u8,
  len: usize,
  life: PhantomData<&'a mut str>,
}

unsafe impl<'a> StableLayout for UniqueStr<'a> {}

impl<'a> Debug for UniqueStr<'a> {
  /// Debug prints as a slice would.
  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
    Debug::fmt(self.deref(), f)
  }
}

impl<'a> Clone for UniqueStr<'a> {
  #[inline(always)]
  fn clone(&self) -> Self {
    *self
  }
}

impl<'a> Copy for UniqueStr<'a> {}

impl<'a> Default for UniqueStr<'a> {
  /// Defaults to an empty string.
  ///
  /// ```rust
  /// # use chromium::*;
  /// let unique: UniqueStr<'static> = UniqueStr::default();
  /// assert_eq!(unique.len(), "".len());
  /// ```
  #[inline(always)]
  fn default() -> Self {
    let life = PhantomData;
    let len = 0;
    let ptr = core::ptr::NonNull::dangling().as_ptr();
    Self { ptr, len, life }
  }
}

impl<'a> Deref for UniqueStr<'a> {
  type Target = str;
  #[inline(always)]
  fn deref(&self) -> &str {
    // Safety: See note at the top of the module.
    unsafe {
      str::from_utf8_unchecked(slice::from_raw_parts(self.ptr, self.len))
    }
  }
}

impl<'a> DerefMut for UniqueStr<'a> {
  #[inline(always)]
  fn deref_mut(&mut self) -> &mut str {
    // Safety: See note at the top of the module.
    unsafe {
      str::from_utf8_unchecked_mut(slice::from_raw_parts_mut(
        self.ptr, self.len,
      ))
    }
  }
}

impl<'a> From<&'a mut str> for UniqueStr<'a> {
  #[inline(always)]
  fn from(s: &'a mut str) -> Self {
    let life = PhantomData;
    let len = s.len();
    let ptr = s.as_mut_ptr();
    Self { ptr, len, life }
  }
}

impl<'a> From<UniqueStr<'a>> for &'a mut str {
  #[inline(always)]
  fn from(unique: UniqueStr<'a>) -> Self {
    // Safety: See note at the top of the module.
    unsafe {
      str::from_utf8_unchecked_mut(slice::from_raw_parts_mut(
        unique.ptr, unique.len,
      ))
    }
  }
}