diff --git a/src/lib.rs b/src/lib.rs index fbd0ef3..4608302 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -262,6 +262,7 @@ impl std::str::FromStr for StackString } } } + impl TryFrom for StackString { type Error = StrTooLargeError; @@ -273,6 +274,19 @@ impl TryFrom for StackString } } + +impl<'a, const SIZE: usize> TryFrom<&'a str> for StackString +{ + type Error = StrTooLargeError; + + #[inline] + fn try_from(from: &'a str) -> Result + { + from.parse() + } +} + + impl TryFrom<[u8; SIZE]> for StackString { type Error = std::str::Utf8Error; diff --git a/src/small.rs b/src/small.rs index 3fd16cf..d1c8c9f 100644 --- a/src/small.rs +++ b/src/small.rs @@ -138,7 +138,7 @@ impl HeapString { impl From for String { - #[inline] + #[inline(always)] fn from(from: HeapString) -> Self { from.into_boxed_str().into() @@ -148,13 +148,51 @@ impl From for String impl From for HeapString { - #[inline] + #[inline(always)] fn from(from: String) -> Self { Self::new(from.into_boxed_str()) } } +impl From> for HeapString +{ + #[inline(always)] + fn from(from: Box) -> Self + { + Self::new(from) + } +} + +impl From for Box +{ + #[inline(always)] + fn from(from: HeapString) -> Self + { + from.into_boxed_str() + } +} + + +impl From for Box<[u8]> +{ + #[inline(always)] + fn from(from: HeapString) -> Self + { + from.into_boxed_bytes() + } +} + +impl<'a> From<&'a str> for HeapString +{ + #[inline(always)] + fn from(from: &'a str) -> Self + { + Self::new(from.into()) + } +} + + impl ops::Drop for HeapString { @@ -396,6 +434,69 @@ impl ops::Deref for SmallString } } +impl<'a, const SIZE: usize> From<&'a str> for SmallString +{ + #[inline] + fn from(string: &'a str) -> Self { + if string.len() <= SIZE { + match StackString::::try_from(string) { + Ok(ss) => return ss.into(), + _ => (), + } + } + // Too large, shunt to heap + HeapString::from(string).into() + } +} + +impl From> for SmallString +{ + #[inline] + fn from(from: StackString) -> Self + { + Self { + inner: SmallStringInner { + stack: ManuallyDrop::new(from), + } + } + } +} + +impl From for SmallString +{ + #[inline(always)] + fn from(from: HeapString) -> Self + { + Self { + inner: SmallStringInner { + heap: ManuallyDrop::new(from), + } + } + } +} + +impl From> for HeapString +{ + #[inline(always)] + fn from(mut from: SmallString) -> Self + { + let h = if from.is_allocated() { + unsafe { + ManuallyDrop::take(&mut from.inner.heap) + } + } else { + unsafe { + from.inner.stack.as_str() + }.into() + }; + std::mem::forget(from); + h + } +} + + + + impl From for SmallString { #[inline] @@ -497,8 +598,8 @@ impl fmt::Write for SmallString let mut buf = [0u8; mem::size_of::()]; unsafe { self.shunt_to_heap_with_unchecked( - std::iter::once_with(|| c.encode_utf8(&mut buf[..])).map(|&mut ref x| x) - ); + std::iter::once_with(|| c.encode_utf8(&mut buf[..])).map(|&mut ref x| x) + ); } } else { // Room in stack for `c` @@ -511,4 +612,39 @@ impl fmt::Write for SmallString } } -//TODO: SmallString: io::Write impls when extending functions have been written +const _:() = { + use std::io::{ + self, + Write, + }; + + impl Write for SmallString + { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let buf = std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + Ok(self.extend_from_str(buf).len()) + } + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + let buf = std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + (self.extend_from_str(buf).len() == buf.len()) + .then(|| ()).ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "failed to write entire buffer")) + } + } +}; + +#[cfg(test)] +mod tests +{ + use super::*; + #[test] + fn extending() + { + let mut ss: SmallString<40> = "Hello world".into(); + } +}