Skip to content

Commit

Permalink
String: make string generic over the storage, like Vec
Browse files Browse the repository at this point in the history
  • Loading branch information
sosthene-nitrokey committed Jun 28, 2024
1 parent 400732b commit c053490
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 30 deletions.
10 changes: 5 additions & 5 deletions src/ser.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use core::hash::{BuildHasher, Hash};

use crate::{
binary_heap::Kind as BinaryHeapKind, BinaryHeap, Deque, IndexMap, IndexSet, LinearMap, String,
Vec,
binary_heap::Kind as BinaryHeapKind, storage::Storage, string::StringInner, BinaryHeap, Deque,
IndexMap, IndexSet, LinearMap, Vec,
};
use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};

Expand Down Expand Up @@ -113,10 +113,10 @@ where

// String containers

impl<const N: usize> Serialize for String<N> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
impl<S: Storage> Serialize for StringInner<S> {
fn serialize<SER>(&self, serializer: SER) -> Result<SER::Ok, SER::Error>
where
S: Serializer,
SER: Serializer,
{
serializer.serialize_str(&*self)
}
Expand Down
65 changes: 40 additions & 25 deletions src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ use core::{
str::{self, Utf8Error},
};

use crate::Vec;
use crate::{
storage::{OwnedStorage, Storage, ViewStorage},
vec::VecInner,
Vec,
};

/// A possible error value when converting a [`String`] from a UTF-16 byte slice.
///
Expand All @@ -33,11 +37,20 @@ impl fmt::Display for FromUtf16Error {
}
}

/// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
pub struct String<const N: usize> {
vec: Vec<u8, N>,
/// Base struct for [`String`] and [`StringView`], generic over the [`Storage`].
///
/// In most cases you should use [`String`] or [`StringView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct StringInner<S: Storage> {
vec: VecInner<u8, S>,
}

/// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
pub type String<const N: usize> = StringInner<OwnedStorage<N>>;

/// A dynamic capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
pub type StringView = StringInner<ViewStorage>;

impl<const N: usize> String<N> {
/// Constructs a new, empty `String` with a fixed capacity of `N` bytes.
///
Expand Down Expand Up @@ -180,7 +193,9 @@ impl<const N: usize> String<N> {
pub fn into_bytes(self) -> Vec<u8, N> {
self.vec
}
}

impl<S: Storage> StringInner<S> {
/// Extracts a string slice containing the entire string.
///
/// # Examples
Expand Down Expand Up @@ -248,7 +263,7 @@ impl<const N: usize> String<N> {
/// assert_eq!(s, "olleh");
/// # Ok::<(), ()>(())
/// ```
pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8, N> {
pub unsafe fn as_mut_vec(&mut self) -> &mut VecInner<u8, S> {
&mut self.vec
}

Expand Down Expand Up @@ -521,26 +536,26 @@ impl<const N: usize> Clone for String<N> {
}
}

impl<const N: usize> fmt::Debug for String<N> {
impl<S: Storage> fmt::Debug for StringInner<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<str as fmt::Debug>::fmt(self, f)
}
}

impl<const N: usize> fmt::Display for String<N> {
impl<S: Storage> fmt::Display for StringInner<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<str as fmt::Display>::fmt(self, f)
}
}

impl<const N: usize> hash::Hash for String<N> {
impl<S: Storage> hash::Hash for StringInner<S> {
#[inline]
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
<str as hash::Hash>::hash(self, hasher)
}
}

impl<const N: usize> fmt::Write for String<N> {
impl<S: Storage> fmt::Write for StringInner<S> {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
self.push_str(s).map_err(|_| fmt::Error)
}
Expand All @@ -550,82 +565,82 @@ impl<const N: usize> fmt::Write for String<N> {
}
}

impl<const N: usize> ops::Deref for String<N> {
impl<S: Storage> ops::Deref for StringInner<S> {
type Target = str;

fn deref(&self) -> &str {
self.as_str()
}
}

impl<const N: usize> ops::DerefMut for String<N> {
impl<S: Storage> ops::DerefMut for StringInner<S> {
fn deref_mut(&mut self) -> &mut str {
self.as_mut_str()
}
}

impl<const N: usize> AsRef<str> for String<N> {
impl<S: Storage> AsRef<str> for StringInner<S> {
#[inline]
fn as_ref(&self) -> &str {
self
}
}

impl<const N: usize> AsRef<[u8]> for String<N> {
impl<S: Storage> AsRef<[u8]> for StringInner<S> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}

impl<const N1: usize, const N2: usize> PartialEq<String<N2>> for String<N1> {
fn eq(&self, rhs: &String<N2>) -> bool {
impl<S1: Storage, S2: Storage> PartialEq<StringInner<S1>> for StringInner<S2> {
fn eq(&self, rhs: &StringInner<S1>) -> bool {
str::eq(&**self, &**rhs)
}
}

// String<N> == str
impl<const N: usize> PartialEq<str> for String<N> {
impl<S: Storage> PartialEq<str> for StringInner<S> {
#[inline]
fn eq(&self, other: &str) -> bool {
str::eq(self, other)
}
}

// String<N> == &'str
impl<const N: usize> PartialEq<&str> for String<N> {
impl<S: Storage> PartialEq<&str> for StringInner<S> {
#[inline]
fn eq(&self, other: &&str) -> bool {
str::eq(self, &other[..])
}
}

// str == String<N>
impl<const N: usize> PartialEq<String<N>> for str {
impl<S: Storage> PartialEq<StringInner<S>> for str {
#[inline]
fn eq(&self, other: &String<N>) -> bool {
fn eq(&self, other: &StringInner<S>) -> bool {
str::eq(self, &other[..])
}
}

// &'str == String<N>
impl<const N: usize> PartialEq<String<N>> for &str {
impl<S: Storage> PartialEq<StringInner<S>> for &str {
#[inline]
fn eq(&self, other: &String<N>) -> bool {
fn eq(&self, other: &StringInner<S>) -> bool {
str::eq(self, &other[..])
}
}

impl<const N: usize> Eq for String<N> {}
impl<S: Storage> Eq for StringInner<S> {}

impl<const N1: usize, const N2: usize> PartialOrd<String<N2>> for String<N1> {
impl<S1: Storage, S2: Storage> PartialOrd<StringInner<S1>> for StringInner<S2> {
#[inline]
fn partial_cmp(&self, other: &String<N2>) -> Option<Ordering> {
fn partial_cmp(&self, other: &StringInner<S1>) -> Option<Ordering> {
PartialOrd::partial_cmp(&**self, &**other)
}
}

impl<const N: usize> Ord for String<N> {
impl<S: Storage> Ord for StringInner<S> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
Ord::cmp(&**self, &**other)
Expand Down

0 comments on commit c053490

Please sign in to comment.