cleanup and add some new methods

This commit is contained in:
missing 2022-12-21 10:31:28 -06:00
parent 222543645e
commit ee38dbc1ad

View file

@ -1,4 +1,4 @@
#![allow(unknown_lints)] // `warn(rustdoc::all)` triggers this for weird nightly reasons #![allow(unknown_lints)] // `warn(rustdoc::all)` triggers this for some reason
#![warn(rustdoc::all)] #![warn(rustdoc::all)]
#![warn(clippy::all)] #![warn(clippy::all)]
#![warn(clippy::pedantic)] #![warn(clippy::pedantic)]
@ -21,14 +21,17 @@ use std::{
/// A smaller [`Cow<'static, str>`](Cow). /// A smaller [`Cow<'static, str>`](Cow).
/// ///
/// This type can represent either an [`&'static str`](prim@str), or a [`String`], and fits within 3 words /// This type can represent either an [`&'static str`](prim@str), or a [`String`], and fits within
/// (the same size as `String`). It does this by storing a capacity of `0` when it is borrowed. /// 3 words (the same size as `String`). It does this by storing a capacity of `0` when it is
/// However, this does mean that it is impossible to distinguish between borrowed and owned when /// borrowed. However, this does mean that it is impossible to distinguish between borrowed and
/// `capacity == len == 0`, but in that case it really doesn't matter much anyway since an owned /// owned when `capacity == len == 0`, but in that case it really doesn't matter much anyway since
/// `String` with capacity equal to zero has not yet allocated. /// an owned `String` with capacity equal to zero has not yet allocated.
/// ///
/// When doing non-mutating actions such as [`Deref::deref`], the string remains in whatever state it /// Note that this method of distinguishing a borrowed string from an owned string still allows
/// was in. When doing mutating actions such as [`DerefMut::deref_mut`], the string becomes owned. /// storing a [`NonNull`] pointer, So this type is *still* 3 words when in an [`Option`].
///
/// When doing non-mutating actions such as [`Deref::deref`], the string remains in whatever state
/// it was in. When doing mutating actions such as [`DerefMut::deref_mut`], the string is made owned.
/// ///
/// ## Mutation as a `String` /// ## Mutation as a `String`
/// ///
@ -149,13 +152,9 @@ impl Stringish {
/// If the `Stringish` is borrowed, the data is copied into a new allocation and the /// If the `Stringish` is borrowed, the data is copied into a new allocation and the
/// `Stringish` becomes owned. Otherwise, nothing happens. /// `Stringish` becomes owned. Otherwise, nothing happens.
pub fn make_owned(&mut self) { pub fn make_owned(&mut self) {
if let None | Some(true) = self.is_owned() { if let Some(s) = self.as_static_str() {
return; *self = Stringish::new_owned(String::from(s));
} }
let mut s = String::with_capacity(self.len);
s.push_str(self);
*self = Stringish::new_owned(s);
} }
/// Converts a `Stringish` into an owned [`String`]. /// Converts a `Stringish` into an owned [`String`].
@ -171,7 +170,48 @@ impl Stringish {
unsafe { String::from_raw_parts(this.ptr.as_ptr(), this.len, this.cap) } unsafe { String::from_raw_parts(this.ptr.as_ptr(), this.len, this.cap) }
} }
// Reborrowing /// Returns the inner [`&'static str`](prim@str) if the `Stringish` is borrowed.
#[must_use]
pub fn as_static_str(&self) -> Option<&'static str> {
if let None | Some(true) = self.is_borrowed() {
// SAFETY: if we are borrowed then we borrow a `&'static str`, so lifetime extension is safe
Some(unsafe { &*(self.as_str() as *const str) })
} else {
None
}
}
/// Converts the `Stringish` into a [`Cow<'static, str>`](Cow).
///
/// This is the inverse of [`Stringish::from_cow`]
#[must_use]
pub fn into_cow(self) -> Cow<'static, str> {
if let Some(s) = self.as_static_str() {
Cow::Borrowed(s)
} else {
Cow::Owned(self.into_owned())
}
}
/// Consumes and leaks the `Stringish`, returning an immutable reference to the contents.
///
/// If the `Stringish` is borrowed, no allocation needs to be created since it already contains
/// a [`&'static str`](prim@str).
///
/// If you wish to get a mutable reference, see [`String::leak`].
#[must_use]
pub fn leak(self) -> &'static str {
if let Some(s) = self.as_static_str() {
s
} else {
// SAFETY: workaround for `String::leak` being unstable
unsafe { str::from_utf8_unchecked(self.into_owned().into_bytes().leak()) }
}
}
/////////////////
// Reborrowing //
/////////////////
/// Returns a byte slice of this `Stringish`'s contents. /// Returns a byte slice of this `Stringish`'s contents.
#[must_use] #[must_use]
@ -239,6 +279,15 @@ impl From<Cow<'static, str>> for Stringish {
} }
} }
/// Converts a `Stringish` into a [`Cow<'static, str>`](Cow).
///
/// See also: [`Stringish::into_cow`]
impl From<Stringish> for Cow<'static, str> {
fn from(stringish: Stringish) -> Self {
stringish.into_cow()
}
}
impl Deref for Stringish { impl Deref for Stringish {
type Target = str; type Target = str;
@ -254,7 +303,9 @@ impl DerefMut for Stringish {
} }
impl Stringish { impl Stringish {
// Mutation as a `String` ////////////////////////////
// Mutation as a `String` //
////////////////////////////
/// Allows mutation of this `Stringish` as a `String` using a guard. /// Allows mutation of this `Stringish` as a `String` using a guard.
/// ///