diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0618acf..15a29c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,18 +15,18 @@ on: inputs: release: type: boolean - description: 'Create a GitHub Release?' + description: "Create a GitHub Release?" default: false required: false publish: type: boolean - description: 'Publish to crates.io?' + description: "Publish to crates.io?" default: false required: false version: type: string - description: 'Version (if $GITHUB_REF is not a tag)' - default: '' + description: "Version (if $GITHUB_REF is not a tag)" + default: "" required: false env: CARGO_TERM_COLOR: always diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 8d3332d..7897570 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] - channel = "stable" + channel = "nightly" components = ["rustfmt", "clippy", "cargo"] - profile = "minimal" \ No newline at end of file + profile = "minimal" diff --git a/src/cow_str.rs b/src/cow_str.rs index 8b5807e..7d7db99 100644 --- a/src/cow_str.rs +++ b/src/cow_str.rs @@ -17,6 +17,7 @@ use core::mem::transmute_copy; use core::ops::Deref; use core::ops::DerefMut; use core::str; +use core::str::FromStr; use crate::inline_str::*; @@ -143,9 +144,7 @@ impl<'i> CowStr<'i> { self.len() == 0 } - /// Converts the `CowStr` into an owned `String`, cloning the data if - /// necessary. - #[deprecated(since = "0.4.0", note = "use `into_string` instead")] + #[deprecated(since = "0.2.0", note = "use `into_string` instead")] #[inline(always)] pub fn into_owned(self) -> String { match self { @@ -155,6 +154,8 @@ impl<'i> CowStr<'i> { } } + /// Converts the `CowStr` into an owned `String`, cloning the data if + /// necessary. #[inline(always)] pub fn into_string(self) -> String { match self { @@ -165,6 +166,18 @@ impl<'i> CowStr<'i> { } } +impl<'i> FromStr for CowStr<'i> { + type Err = (); + + #[inline(always)] + fn from_str(s: &str) -> Result { + match InlineStr::try_from(s) { + Ok(inline) => Ok(CowStr::Inlined(inline)), + Err(_) => Ok(CowStr::Owned(s.to_string().into_boxed_str())), + } + } +} + impl<'i> Display for CowStr<'i> { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -396,6 +409,77 @@ impl<'i> From> for String { } } +#[cfg(not(feature = "is_variant"))] +impl<'i> CowStr<'i> { + /// Returns `true` if the `CowStr` is the `Owned` variant. + #[inline(always)] + pub const fn is_owned(&self) -> bool { + matches!(self, CowStr::Owned(_)) + } + + /// Returns `true` if the `CowStr` is the `Inlined` variant. + #[inline(always)] + pub const fn is_inlined(&self) -> bool { + matches!(self, CowStr::Inlined(_)) + } + + /// Returns `true` if the `CowStr` is the `Borrowed` variant. + #[inline(always)] + pub const fn is_borrowed(&self) -> bool { + matches!(self, CowStr::Borrowed(_)) + } +} + +impl CowStr<'_> { + /// Attempts to create an inline `CowStr` from a value that can be converted + /// to a string slice via an `AsRef` impl. + /// + /// Returns an error if the string is too long to be inlined. + #[inline(always)] + pub fn try_inline<'i, T: 'i + AsRef>( + s: T, + ) -> Result, StringTooLongError> { + let inline = InlineStr::try_from(s.as_ref())?; + Ok(CowStr::Inlined(inline)) + } + + /// Creates an inline `CowStr` from a value that can be converted to a string + /// slice via an `AsRef` impl, panicking if the string is too long to be + /// inlined. + /// + /// # Panics + /// + /// Panics if the string length exceeds [`MAX_INLINE_STR_LEN`]. + #[inline(always)] + pub fn inline<'i, T: 'i + AsRef>(s: T) -> CowStr<'i> { + let inline = + InlineStr::try_from(s.as_ref()).expect("String too long to inline!"); + CowStr::Inlined(inline) + } + + /// Forcibly creates an inline `CowStr` from a given value that can be + /// converted to a string slice via an `AsRef` impl, truncating it if + /// necessary to fit within the maximum inline length. + #[inline(always)] + pub fn force_inline<'i, T: 'i + AsRef>(s: T) -> CowStr<'i> { + let src = s.as_ref().as_bytes(); + let mut len = src.len(); + if len > MAX_INLINE_STR_LEN { + len = MAX_INLINE_STR_LEN; + } + let mut buf = [0u8; MAX_INLINE_STR_LEN]; + buf[..len].copy_from_slice(&src[..len]); + let len = len as u8; + CowStr::Inlined(InlineStr { buf, len }) + } + + /// Creates an inline `CowStr` from a single character. + #[inline(always)] + pub fn from_char(c: char) -> CowStr<'static> { + CowStr::Inlined(c.into()) + } +} + #[cfg(feature = "serde")] mod serde_impl { use core::fmt;