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(clippy::all)]
#![warn(clippy::pedantic)]
@ -21,14 +21,17 @@ use std::{
/// A smaller [`Cow<'static, str>`](Cow).
///
/// This type can represent either an [`&'static str`](prim@str), or a [`String`], and fits within 3 words
/// (the same size as `String`). It does this by storing a capacity of `0` when it is borrowed.
/// However, this does mean that it is impossible to distinguish between borrowed and owned when
/// `capacity == len == 0`, but in that case it really doesn't matter much anyway since an owned
/// `String` with capacity equal to zero has not yet allocated.
/// This type can represent either an [`&'static str`](prim@str), or a [`String`], and fits within
/// 3 words (the same size as `String`). It does this by storing a capacity of `0` when it is
/// borrowed. However, this does mean that it is impossible to distinguish between borrowed and
/// owned when `capacity == len == 0`, but in that case it really doesn't matter much anyway since
/// 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
/// was in. When doing mutating actions such as [`DerefMut::deref_mut`], the string becomes owned.
/// Note that this method of distinguishing a borrowed string from an owned string still allows
/// 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`
///
@ -149,13 +152,9 @@ impl Stringish {
/// If the `Stringish` is borrowed, the data is copied into a new allocation and the
/// `Stringish` becomes owned. Otherwise, nothing happens.
pub fn make_owned(&mut self) {
if let None | Some(true) = self.is_owned() {
return;
if let Some(s) = self.as_static_str() {
*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`].
@ -171,7 +170,48 @@ impl Stringish {
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.
#[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 {
type Target = str;
@ -254,7 +303,9 @@ impl DerefMut for Stringish {
}
impl Stringish {
// Mutation as a `String`
////////////////////////////
// Mutation as a `String` //
////////////////////////////
/// Allows mutation of this `Stringish` as a `String` using a guard.
///