blob: f9864af8e1d7aac2623165cf3fe442dd83f759c6 [file] [log] [blame]
//! Aliasable `String`.
use core::ops::{Deref, DerefMut};
use core::pin::Pin;
use core::{fmt, str};
use crate::vec::AliasableVec;
pub use alloc::string::String as UniqueString;
/// Basic aliasable (non `core::ptr::Unique`) alternative to
/// [`alloc::string::String`].
pub struct AliasableString(AliasableVec<u8>);
impl AliasableString {
/// Consumes `self` into an [`AliasableVec`] of UTF-8 bytes.
pub fn into_bytes(self) -> AliasableVec<u8> {
self.0
}
/// Construct an `AliasableString` from a [`UniqueString`].
pub fn from_unique(s: UniqueString) -> Self {
Self(s.into_bytes().into())
}
/// Consumes `self` and converts it into a non-aliasable [`UniqueString`].
#[inline]
pub fn into_unique(s: AliasableString) -> UniqueString {
let unique_bytes = s.into_bytes().into();
unsafe { UniqueString::from_utf8_unchecked(unique_bytes) }
}
/// Convert a pinned [`AliasableString`] to a `core::ptr::Unique` backed pinned
/// [`UniqueString`].
pub fn into_unique_pin(pin: Pin<AliasableString>) -> Pin<UniqueString> {
// SAFETY: The pointer is not changed, just the container.
unsafe {
let aliasable = Pin::into_inner_unchecked(pin);
Pin::new_unchecked(AliasableString::into_unique(aliasable))
}
}
/// Convert a pinned `core::ptr::Unique` backed [`UniqueString`] to a
/// pinned [`AliasableString`].
pub fn from_unique_pin(pin: Pin<UniqueString>) -> Pin<AliasableString> {
// SAFETY: The pointer is not changed, just the container.
unsafe {
let unique = Pin::into_inner_unchecked(pin);
Pin::new_unchecked(AliasableString::from(unique))
}
}
}
impl From<UniqueString> for AliasableString {
#[inline]
fn from(s: UniqueString) -> Self {
Self::from_unique(s)
}
}
impl From<AliasableString> for UniqueString {
#[inline]
fn from(s: AliasableString) -> Self {
AliasableString::into_unique(s)
}
}
impl Deref for AliasableString {
type Target = str;
#[inline]
fn deref(&self) -> &str {
// SAFETY: `AliasableString` will only ever contain UTF-8.
unsafe { str::from_utf8_unchecked(&*self.0) }
}
}
impl DerefMut for AliasableString {
#[inline]
fn deref_mut(&mut self) -> &mut str {
// SAFETY: `AliasableString` will only ever contain UTF-8.
unsafe { str::from_utf8_unchecked_mut(&mut *self.0) }
}
}
impl AsRef<str> for AliasableString {
#[inline]
fn as_ref(&self) -> &str {
&*self
}
}
impl AsMut<str> for AliasableString {
fn as_mut(&mut self) -> &mut str {
&mut *self
}
}
impl fmt::Debug for AliasableString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_ref(), f)
}
}
#[cfg(feature = "traits")]
unsafe impl crate::StableDeref for AliasableString {}
#[cfg(feature = "traits")]
unsafe impl crate::AliasableDeref for AliasableString {}
#[cfg(test)]
mod tests {
use super::{AliasableString, AliasableVec, UniqueString};
use alloc::{format, vec};
use core::pin::Pin;
#[test]
fn test_new() {
let aliasable = AliasableString::from_unique(UniqueString::from("hello"));
assert_eq!(&*aliasable, &"hello"[..]);
let unique = AliasableString::into_unique(aliasable);
assert_eq!(&*unique, &"hello"[..]);
}
#[test]
fn test_new_pin() {
let aliasable = AliasableString::from_unique_pin(Pin::new(UniqueString::from("hello")));
assert_eq!(&*aliasable, &"hello"[..]);
let unique = AliasableString::into_unique_pin(aliasable);
assert_eq!(&*unique, &"hello"[..]);
}
#[test]
fn test_refs() {
let mut aliasable = AliasableString::from_unique(UniqueString::from("hello"));
let ptr: *const str = &*aliasable;
let as_mut_ptr: *const str = aliasable.as_mut();
let as_ref_ptr: *const str = aliasable.as_ref();
assert_eq!(ptr, as_mut_ptr);
assert_eq!(ptr, as_ref_ptr);
}
#[test]
fn test_debug() {
let aliasable = AliasableString::from_unique(UniqueString::from("hello"));
assert_eq!(format!("{:?}", aliasable), "\"hello\"");
}
#[test]
fn test_into_bytes() {
let aliasable = AliasableString::from_unique(UniqueString::from("hello"));
assert_eq!(
AliasableVec::into_unique(aliasable.into_bytes()),
vec![b'h', b'e', b'l', b'l', b'o']
);
}
}