Skip to content

Commit

Permalink
Return Option from InlineString::from_str
Browse files Browse the repository at this point in the history
  • Loading branch information
GnomedDev committed Mar 10, 2024
1 parent 0223aca commit 57a570b
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 22 deletions.
1 change: 1 addition & 0 deletions src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ impl<T: Clone, LenT: ValidLength> Clone for FixedArray<T, LenT> {
unsafe { Self::from_box_with_nonzero(ptr, self.len) }
}

#[allow(clippy::assigning_clones)]
fn clone_from(&mut self, source: &Self) {
if self.len() == source.len() {
self.clone_from_slice(source);
Expand Down
14 changes: 10 additions & 4 deletions src/inline.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::mem::size_of;

use crate::ValidLength;

#[cfg(feature = "typesize")]
Expand Down Expand Up @@ -61,16 +63,20 @@ impl<StrRepr: Copy + AsRef<[u8]> + AsMut<[u8]> + Default + TypeSize> InlineStrin
StrRepr::default().as_ref().len()
}

pub fn from_str(val: &str) -> Self {
pub fn from_str(val: &str) -> Option<Self> {
let mut arr = StrRepr::default();
if val.len() > size_of::<Self>() {
return None;
}

arr.as_mut()[..val.len()].copy_from_slice(val.as_bytes());

if val.len() != Self::max_len() {
// 0xFF terminate the string, to gain an extra inline character
arr.as_mut()[val.len()] = Self::TERMINATOR;
}

Self { arr }
Some(Self { arr })
}

pub fn len(&self) -> u8 {
Expand Down Expand Up @@ -102,7 +108,7 @@ mod tests {
Repr: Copy + AsRef<[u8]> + AsMut<[u8]> + Default + TypeSize,
{
let inline = InlineString::<Repr>::from_str(original);
assert_eq!(original, inline.as_str());
assert_eq!(original, inline.expect("should not overflow").as_str());
}

fn check_roundtrip_repr<Repr: Copy + AsRef<[u8]> + AsMut<[u8]> + Default + TypeSize>() {
Expand All @@ -120,7 +126,7 @@ mod tests {
}

#[test]
#[should_panic(expected = "range end index 9 out of range for slice of length 8")]
#[should_panic(expected = "should not overflow")]
fn check_overflow() {
check_roundtrip::<[u8; 8]>("012345678");
}
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
#![cfg_attr(feature = "nightly", feature(portable_simd))]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "std", allow(unused_imports))]
#![warn(clippy::pedantic, clippy::as_conversions)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::module_name_repetitions, unknown_lints)]

extern crate alloc;

Expand Down
34 changes: 17 additions & 17 deletions src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use alloc::{
string::{String, ToString},
sync::Arc,
};
use core::{borrow::Borrow, cmp::PartialEq, fmt::Write as _, hash::Hash};
use core::{borrow::Borrow, fmt::Write as _, hash::Hash};

use crate::{
array::FixedArray,
inline::{get_heap_threshold, InlineString},
inline::InlineString,
length::{InvalidStrLength, SmallLen, ValidLength},
r#static::StaticStr,
};
Expand Down Expand Up @@ -45,10 +45,10 @@ impl<LenT: ValidLength> FixedString<LenT> {
Self::from_static_trunc("")
}

/// # Panics
/// Panics if val does not fit in the heap threshold.
pub(crate) fn new_inline(val: &str) -> Self {
Self(FixedStringRepr::Inline(InlineString::from_str(val)))
pub(crate) fn new_inline(val: &str) -> Option<Self> {
InlineString::from_str(val)
.map(FixedStringRepr::Inline)
.map(Self)
}

/// Converts a `&'static str` into a [`FixedString`].
Expand All @@ -75,11 +75,11 @@ impl<LenT: ValidLength> FixedString<LenT> {
/// See [`Self::from_string_trunc`] for truncation behaviour.
#[must_use]
pub fn from_str_trunc(val: &str) -> Self {
if val.len() <= get_heap_threshold::<LenT>() {
return Self::new_inline(val);
if let Some(inline) = Self::new_inline(val) {
inline
} else {
Self::from_string_trunc(val.to_owned())
}

Self::from_string_trunc(val.to_owned())
}

/// Converts a [`String`] into a [`FixedString`], **truncating** if the value is larger than `LenT`'s maximum.
Expand Down Expand Up @@ -166,6 +166,7 @@ impl<LenT: ValidLength> Clone for FixedString<LenT> {
fn clone_from(&mut self, source: &Self) {
match (&mut self.0, &source.0) {
(FixedStringRepr::Heap(new), FixedStringRepr::Heap(src)) => new.clone_from(src),
#[allow(clippy::assigning_clones)]
_ => *self = source.clone(),
}
}
Expand Down Expand Up @@ -251,9 +252,8 @@ impl<LenT: ValidLength> TryFrom<Box<str>> for FixedString<LenT> {
type Error = InvalidStrLength;

fn try_from(value: Box<str>) -> Result<Self, Self::Error> {
if value.len() <= get_heap_threshold::<LenT>() {
let inner = InlineString::from_str(&value);
return Ok(Self(FixedStringRepr::Inline(inner)));
if let Some(inline) = Self::new_inline(&value) {
return Ok(inline);
}

match value.into_boxed_bytes().try_into() {
Expand Down Expand Up @@ -329,11 +329,11 @@ impl<'de, LenT: ValidLength> serde::Deserialize<'de> for FixedString<LenT> {
}

fn visit_str<E: serde::de::Error>(self, val: &str) -> Result<Self::Value, E> {
if val.len() <= get_heap_threshold::<LenT>() {
return Ok(FixedString::new_inline(val));
if let Some(inline) = FixedString::new_inline(val) {
Ok(inline)
} else {
FixedString::try_from(Box::from(val)).map_err(E::custom)
}

FixedString::try_from(Box::from(val)).map_err(E::custom)
}

fn visit_string<E: serde::de::Error>(self, val: String) -> Result<Self::Value, E> {
Expand Down

0 comments on commit 57a570b

Please sign in to comment.