summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--Cargo.toml8
-rw-r--r--src/hash.rs39
-rw-r--r--src/lib.rs9
-rw-r--r--src/non_empty_str.rs355
-rw-r--r--src/non_empty_string.rs378
6 files changed, 794 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..784eed7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.hgignore
+.hg/
+.vscode/
+target/
+Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..7739a36
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "ministr"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/hash.rs b/src/hash.rs
new file mode 100644
index 0000000..0e9ba6d
--- /dev/null
+++ b/src/hash.rs
@@ -0,0 +1,39 @@
+use std::{
+ collections::hash_map::DefaultHasher,
+ hash::{Hash, Hasher},
+};
+
+/// Hashes the string literal `s` to a `u64` using the Rust's [`default hasher`](DefaultHasher) (i.e. one used in the [`HashMap`](std::collections::HashMap)).
+pub fn str_hash_default(s: &str) -> u64 {
+ let mut hasher = DefaultHasher::new();
+ s.hash(&mut hasher);
+ hasher.finish()
+}
+
+/// Hashes the string literal `s` to a `u32` using the FNV1a (32b) hash.
+pub fn str_hash_fnv1a(s: &str) -> u32 {
+ const FNV1A32_PRIME: u32 = 0x0100_0193;
+ const FNV1A32_SEED: u32 = 0x811C_9DC5;
+
+ let mut hash = FNV1A32_SEED;
+
+ for byte in s.as_bytes() {
+ hash = (hash ^ *byte as u32).wrapping_mul(FNV1A32_PRIME);
+ }
+
+ hash
+}
+
+/// Hashes the string literal `s` to a `u64` using the FNV1a (64b) hash.
+pub fn str_hash_fnv1a_64(s: &str) -> u64 {
+ const FNV1A64_PRIME: u64 = 0x0000_0100_0000_01B3;
+ const FNV1A64_SEED: u64 = 0xcbf2_9ce4_8422_2325;
+
+ let mut hash = FNV1A64_SEED;
+
+ for byte in s.as_bytes() {
+ hash = (hash ^ *byte as u64).wrapping_mul(FNV1A64_PRIME);
+ }
+
+ hash
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..48b4a9c
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,9 @@
+//! Exports some string utility types and functions.
+
+mod hash;
+mod non_empty_str;
+mod non_empty_string;
+
+pub use hash::*;
+pub use non_empty_str::*;
+pub use non_empty_string::*;
diff --git a/src/non_empty_str.rs b/src/non_empty_str.rs
new file mode 100644
index 0000000..83654f9
--- /dev/null
+++ b/src/non_empty_str.rs
@@ -0,0 +1,355 @@
+use {
+ crate::*,
+ std::{
+ borrow::ToOwned,
+ cmp::PartialEq,
+ convert::TryFrom,
+ fmt::{Display, Formatter},
+ ops::Deref,
+ },
+};
+
+/// A non-empty string slice.
+/// [`NonEmptyString`] is the owned version.
+#[repr(transparent)]
+#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct NonEmptyStr(str);
+
+impl NonEmptyStr {
+ /// Tries to create a [`NonEmptyStr`] from the string slice `s`.
+ /// Returns `None` if the string `s` is empty.
+ pub fn new(s: &str) -> Option<&Self> {
+ if s.is_empty() {
+ None
+ } else {
+ Some(unsafe { Self::new_unchecked(s) })
+ }
+ }
+
+ /// Creates a [`NonEmptyStr`] from the string slice `s`
+ /// without checking if it is empty.
+ ///
+ /// # Safety
+ /// The caller guarantees the string `s` is not empty.
+ /// Passing an empty string slice is undefined behaviour.
+ ///
+ /// # Panics
+ /// Panics in debug configuration only if the `s` is empty.
+ pub unsafe fn new_unchecked(s: &str) -> &Self {
+ debug_assert!(
+ !s.is_empty(),
+ "tried to create a non-empty string slice from an empty source"
+ );
+ &*(s as *const str as *const _)
+ }
+
+ pub fn as_str(&self) -> &str {
+ &self.0
+ }
+
+ pub fn inner(&self) -> &str {
+ &self.0
+ }
+}
+
+impl Deref for NonEmptyStr {
+ type Target = str;
+
+ fn deref(&self) -> &Self::Target {
+ self.inner()
+ }
+}
+
+impl<'s> AsRef<str> for &'s NonEmptyStr {
+ fn as_ref(&self) -> &str {
+ self.inner()
+ }
+}
+
+impl ToOwned for NonEmptyStr {
+ type Owned = NonEmptyString;
+
+ fn to_owned(&self) -> Self::Owned {
+ self.into()
+ }
+}
+
+// Fallible conversions from string slices and owned strings.
+////////////////////////////////////////////////////////////
+impl<'s> TryFrom<&'s str> for &'s NonEmptyStr {
+ type Error = ();
+
+ fn try_from(s: &'s str) -> Result<Self, Self::Error> {
+ NonEmptyStr::new(s).ok_or(())
+ }
+}
+
+impl<'s> TryFrom<&'s String> for &'s NonEmptyStr {
+ type Error = ();
+
+ fn try_from(s: &'s String) -> Result<Self, Self::Error> {
+ NonEmptyStr::new(s).ok_or(())
+ }
+}
+////////////////////////////////////////////////////////////
+
+// Infallible conversion from a non-empty owned string.
+////////////////////////////////////////////////////////////
+impl<'s> From<&'s NonEmptyString> for &'s NonEmptyStr {
+ fn from(s: &'s NonEmptyString) -> Self {
+ s.as_ne_str()
+ }
+}
+////////////////////////////////////////////////////////////
+
+// Conversions into string slices and owned strings.
+// Conversion into a non-empty owned string is implemented by a `From` on it.
+////////////////////////////////////////////////////////////
+impl<'s> Into<&'s str> for &'s NonEmptyStr {
+ fn into(self) -> &'s str {
+ self.as_str()
+ }
+}
+
+impl<'s> Into<String> for &'s NonEmptyStr {
+ fn into(self) -> String {
+ self.0.to_owned()
+ }
+}
+////////////////////////////////////////////////////////////
+
+// Comparsions.
+
+// <NonEmptyStr>
+////////////////////////////////////////////////////////////
+impl PartialEq<&NonEmptyStr> for NonEmptyStr {
+ fn eq(&self, other: &&NonEmptyStr) -> bool {
+ PartialEq::eq(self, *other)
+ }
+
+ fn ne(&self, other: &&NonEmptyStr) -> bool {
+ PartialEq::ne(self, *other)
+ }
+}
+
+impl PartialEq<NonEmptyStr> for &NonEmptyStr {
+ fn eq(&self, other: &NonEmptyStr) -> bool {
+ PartialEq::eq(*self, other)
+ }
+
+ fn ne(&self, other: &NonEmptyStr) -> bool {
+ PartialEq::ne(*self, other)
+ }
+}
+////////////////////////////////////////////////////////////
+
+/// <str>
+////////////////////////////////////////////////////////////
+impl PartialEq<str> for NonEmptyStr {
+ fn eq(&self, other: &str) -> bool {
+ PartialEq::eq(self.as_str(), other)
+ }
+
+ fn ne(&self, other: &str) -> bool {
+ PartialEq::ne(self.as_str(), other)
+ }
+}
+
+impl PartialEq<&str> for NonEmptyStr {
+ fn eq(&self, other: &&str) -> bool {
+ PartialEq::eq(self.as_str(), *other)
+ }
+
+ fn ne(&self, other: &&str) -> bool {
+ PartialEq::ne(self.as_str(), *other)
+ }
+}
+
+impl PartialEq<str> for &NonEmptyStr {
+ fn eq(&self, other: &str) -> bool {
+ PartialEq::eq(self.as_str(), other)
+ }
+
+ fn ne(&self, other: &str) -> bool {
+ PartialEq::ne(self.as_str(), other)
+ }
+}
+////////////////////////////////////////////////////////////
+
+/// <String>
+////////////////////////////////////////////////////////////
+impl PartialEq<String> for NonEmptyStr {
+ fn eq(&self, other: &String) -> bool {
+ PartialEq::eq(self.as_str(), other.as_str())
+ }
+
+ fn ne(&self, other: &String) -> bool {
+ PartialEq::ne(self.as_str(), other.as_str())
+ }
+}
+
+impl PartialEq<&String> for NonEmptyStr {
+ fn eq(&self, other: &&String) -> bool {
+ PartialEq::eq(self.as_str(), other.as_str())
+ }
+
+ fn ne(&self, other: &&String) -> bool {
+ PartialEq::ne(self.as_str(), other.as_str())
+ }
+}
+
+impl PartialEq<String> for &NonEmptyStr {
+ fn eq(&self, other: &String) -> bool {
+ PartialEq::eq(self.as_str(), other.as_str())
+ }
+
+ fn ne(&self, other: &String) -> bool {
+ PartialEq::ne(self.as_str(), other.as_str())
+ }
+}
+////////////////////////////////////////////////////////////
+
+/// <NonEmptyString>
+////////////////////////////////////////////////////////////
+impl PartialEq<NonEmptyString> for NonEmptyStr {
+ fn eq(&self, other: &NonEmptyString) -> bool {
+ PartialEq::eq(self, other.as_ne_str())
+ }
+
+ fn ne(&self, other: &NonEmptyString) -> bool {
+ PartialEq::ne(self, other.as_ne_str())
+ }
+}
+
+impl PartialEq<&NonEmptyString> for NonEmptyStr {
+ fn eq(&self, other: &&NonEmptyString) -> bool {
+ PartialEq::eq(self, other.as_ne_str())
+ }
+
+ fn ne(&self, other: &&NonEmptyString) -> bool {
+ PartialEq::ne(self, other.as_ne_str())
+ }
+}
+
+impl PartialEq<NonEmptyString> for &NonEmptyStr {
+ fn eq(&self, other: &NonEmptyString) -> bool {
+ PartialEq::eq(self, other.as_ne_str())
+ }
+
+ fn ne(&self, other: &NonEmptyString) -> bool {
+ PartialEq::ne(self, other.as_ne_str())
+ }
+}
+////////////////////////////////////////////////////////////
+
+impl<'s> Display for &'s NonEmptyStr {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ self.inner().fmt(f)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ fn cmp(nes: &NonEmptyStr, s: &str) {
+ assert_eq!(nes, s);
+ //assert_eq!(s, nes);
+ assert_eq!(&nes[..], s);
+ assert_eq!(nes.as_ref(), s);
+ assert_eq!(nes.as_str(), s);
+ assert_eq!(nes.deref(), s);
+ assert_eq!(nes.inner(), s);
+ }
+
+ #[test]
+ fn non_empty_str() {
+ let foo = "foo";
+ let foo_str = foo.to_owned();
+ let ne_foo_str = NonEmptyString::new(foo_str.clone()).unwrap();
+
+ // `new()` from non-empty slice
+ let ne_foo = NonEmptyStr::new(foo).unwrap();
+ cmp(ne_foo, foo);
+
+ assert_eq!(ne_foo, ne_foo);
+ assert_eq!(ne_foo, &ne_foo);
+ assert_eq!(&ne_foo, ne_foo);
+ assert_eq!(&ne_foo, &ne_foo);
+ assert_eq!(ne_foo, *ne_foo);
+ assert_eq!(*ne_foo, ne_foo);
+ assert_eq!(*ne_foo, *ne_foo);
+
+ // `new()` from empty slice
+ let empty = "";
+ assert!(NonEmptyStr::new(empty).is_none());
+
+ // `unchecked_new()` from non-empty slice
+ {
+ let ne_foo = unsafe { NonEmptyStr::new_unchecked(foo) };
+ cmp(ne_foo, foo);
+ }
+
+ // from `NonEmptyString`.
+ {
+ let ne_foo: &NonEmptyStr = (&ne_foo_str).into();
+ cmp(ne_foo, foo);
+
+ let ne_foo = <&NonEmptyStr as From<&NonEmptyString>>::from(&ne_foo_str);
+ cmp(ne_foo, foo);
+ }
+
+ // try from non-empty slice
+ {
+ use std::convert::TryInto;
+
+ let ne_foo: &NonEmptyStr = foo.try_into().unwrap();
+ cmp(ne_foo, foo);
+
+ let ne_foo = <&NonEmptyStr as TryFrom<&str>>::try_from(foo).unwrap();
+ cmp(ne_foo, foo);
+ }
+
+ // try from empty slice
+ {
+ use std::convert::TryInto;
+
+ let ne_foo: Result<&NonEmptyStr, _> = "".try_into();
+ assert!(ne_foo.is_err());
+
+ let ne_foo = <&NonEmptyStr as TryFrom<&str>>::try_from("");
+ assert!(ne_foo.is_err());
+ }
+
+ // try from non-empty `String`
+ {
+ use std::convert::TryInto;
+
+ let ne_foo: &NonEmptyStr = (&foo_str).try_into().unwrap();
+ cmp(ne_foo, foo);
+
+ let ne_foo = <&NonEmptyStr as TryFrom<&String>>::try_from(&foo_str).unwrap();
+ cmp(ne_foo, foo);
+ }
+
+ // try from empty `String`
+ {
+ use std::convert::TryInto;
+
+ let empty_str = "".to_owned();
+
+ let ne_foo: Result<&NonEmptyStr, _> = (&empty_str).try_into();
+ assert!(ne_foo.is_err());
+
+ let ne_foo = <&NonEmptyStr as TryFrom<&String>>::try_from(&empty_str);
+ assert!(ne_foo.is_err());
+ }
+ }
+
+ #[cfg(debug_assertions)]
+ #[test]
+ #[should_panic(expected = "tried to create a non-empty string slice from an empty source")]
+ fn new_unchecked_panic() {
+ let _ = unsafe { NonEmptyStr::new_unchecked("") };
+ }
+}
diff --git a/src/non_empty_string.rs b/src/non_empty_string.rs
new file mode 100644
index 0000000..8ad7400
--- /dev/null
+++ b/src/non_empty_string.rs
@@ -0,0 +1,378 @@
+use {
+ crate::*,
+ std::{
+ borrow::Borrow,
+ cmp::PartialEq,
+ convert::TryFrom,
+ fmt::{Display, Formatter},
+ ops::Deref,
+ },
+};
+
+/// A non-empty [`String`].
+/// [`NonEmptyStr`] is the borrowed version.
+#[repr(transparent)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct NonEmptyString(String);
+
+impl NonEmptyString {
+ /// Tries to create a [`NonEmptyString`] from the string `s`.
+ /// Returns `None` if the string `s` is empty.
+ pub fn new(s: String) -> Option<Self> {
+ if s.is_empty() {
+ None
+ } else {
+ Some(Self(s))
+ }
+ }
+
+ /// Creates a [`NonEmptyString`] from the string `s`
+ /// without checking if it is empty.
+ ///
+ /// # Safety
+ /// The caller guarantees the string `s` is not empty.
+ /// Passing an empty string is undefined behaviour.
+ ///
+ /// # Panics
+ /// Panics in debug configuration only if the string `s` is empty.
+ pub unsafe fn new_unchecked(s: String) -> Self {
+ debug_assert!(
+ !s.is_empty(),
+ "tried to create a non-empty string from an empty source"
+ );
+ Self(s)
+ }
+
+ /// Creates a [`NonEmptyString`] from the [`non-empty string slice`](NonEmptyStr) `s`.
+ pub fn from(s: &NonEmptyStr) -> Self {
+ unsafe { NonEmptyString::new_unchecked(s.inner().to_owned()) }
+ }
+
+ pub fn as_str(&self) -> &str {
+ self.0.as_str()
+ }
+
+ pub fn as_ne_str(&self) -> &NonEmptyStr {
+ unsafe { NonEmptyStr::new_unchecked(&self.0) }
+ }
+
+ pub fn inner(&self) -> &String {
+ &self.0
+ }
+
+ pub fn into_inner(self) -> String {
+ self.0
+ }
+}
+
+impl Deref for NonEmptyString {
+ type Target = NonEmptyStr;
+
+ fn deref(&self) -> &Self::Target {
+ self.as_ne_str()
+ }
+}
+
+impl AsRef<NonEmptyStr> for NonEmptyString {
+ fn as_ref(&self) -> &NonEmptyStr {
+ self.as_ne_str()
+ }
+}
+
+impl AsRef<String> for NonEmptyString {
+ fn as_ref(&self) -> &String {
+ self.inner()
+ }
+}
+
+impl AsRef<str> for NonEmptyString {
+ fn as_ref(&self) -> &str {
+ self.as_str()
+ }
+}
+
+impl Borrow<NonEmptyStr> for NonEmptyString {
+ fn borrow(&self) -> &NonEmptyStr {
+ self.as_ne_str()
+ }
+}
+
+// Fallible conversions from string slices and owned strings.
+////////////////////////////////////////////////////////////
+impl<'s> TryFrom<&'s str> for NonEmptyString {
+ type Error = ();
+
+ fn try_from(s: &'s str) -> Result<Self, Self::Error> {
+ Self::new(s.to_owned()).ok_or(())
+ }
+}
+
+impl TryFrom<String> for NonEmptyString {
+ type Error = ();
+
+ fn try_from(s: String) -> Result<Self, Self::Error> {
+ Self::new(s).ok_or(())
+ }
+}
+////////////////////////////////////////////////////////////
+
+// Infallible conversion from a non-empty string slice.
+////////////////////////////////////////////////////////////
+impl<'s> From<&'s NonEmptyStr> for NonEmptyString {
+ fn from(s: &'s NonEmptyStr) -> Self {
+ Self::from(s)
+ }
+}
+////////////////////////////////////////////////////////////
+
+// Conversions into string slices and owned strings.
+////////////////////////////////////////////////////////////
+impl<'s> Into<&'s str> for &'s NonEmptyString {
+ fn into(self) -> &'s str {
+ self.as_str()
+ }
+}
+
+impl Into<String> for NonEmptyString {
+ fn into(self) -> String {
+ self.into_inner()
+ }
+}
+////////////////////////////////////////////////////////////
+
+// Comparsions.
+
+// <NonEmptyString>
+////////////////////////////////////////////////////////////
+impl PartialEq<&NonEmptyString> for NonEmptyString {
+ fn eq(&self, other: &&NonEmptyString) -> bool {
+ PartialEq::eq(self, *other)
+ }
+
+ fn ne(&self, other: &&NonEmptyString) -> bool {
+ PartialEq::ne(self, *other)
+ }
+}
+
+impl PartialEq<NonEmptyString> for &NonEmptyString {
+ fn eq(&self, other: &NonEmptyString) -> bool {
+ PartialEq::eq(*self, other)
+ }
+
+ fn ne(&self, other: &NonEmptyString) -> bool {
+ PartialEq::ne(*self, other)
+ }
+}
+////////////////////////////////////////////////////////////
+
+/// <str>
+////////////////////////////////////////////////////////////
+impl PartialEq<str> for NonEmptyString {
+ fn eq(&self, other: &str) -> bool {
+ PartialEq::eq(self.as_str(), other)
+ }
+
+ fn ne(&self, other: &str) -> bool {
+ PartialEq::ne(self.as_str(), other)
+ }
+}
+
+impl PartialEq<&str> for NonEmptyString {
+ fn eq(&self, other: &&str) -> bool {
+ PartialEq::eq(self.as_str(), *other)
+ }
+
+ fn ne(&self, other: &&str) -> bool {
+ PartialEq::ne(self.as_str(), *other)
+ }
+}
+
+impl PartialEq<str> for &NonEmptyString {
+ fn eq(&self, other: &str) -> bool {
+ PartialEq::eq(self.as_str(), other)
+ }
+
+ fn ne(&self, other: &str) -> bool {
+ PartialEq::ne(self.as_str(), other)
+ }
+}
+////////////////////////////////////////////////////////////
+
+/// <String>
+////////////////////////////////////////////////////////////
+impl PartialEq<String> for NonEmptyString {
+ fn eq(&self, other: &String) -> bool {
+ PartialEq::eq(self.as_str(), other.as_str())
+ }
+
+ fn ne(&self, other: &String) -> bool {
+ PartialEq::ne(self.as_str(), other.as_str())
+ }
+}
+
+impl PartialEq<&String> for NonEmptyString {
+ fn eq(&self, other: &&String) -> bool {
+ PartialEq::eq(self.as_str(), other.as_str())
+ }
+
+ fn ne(&self, other: &&String) -> bool {
+ PartialEq::ne(self.as_str(), other.as_str())
+ }
+}
+
+impl PartialEq<String> for &NonEmptyString {
+ fn eq(&self, other: &String) -> bool {
+ PartialEq::eq(self.as_str(), other.as_str())
+ }
+
+ fn ne(&self, other: &String) -> bool {
+ PartialEq::ne(self.as_str(), other.as_str())
+ }
+}
+////////////////////////////////////////////////////////////
+
+/// <NonEmptyStr>
+////////////////////////////////////////////////////////////
+impl PartialEq<NonEmptyStr> for NonEmptyString {
+ fn eq(&self, other: &NonEmptyStr) -> bool {
+ PartialEq::eq(self.as_ne_str(), other)
+ }
+
+ fn ne(&self, other: &NonEmptyStr) -> bool {
+ PartialEq::ne(self.as_ne_str(), other)
+ }
+}
+
+impl PartialEq<&NonEmptyStr> for NonEmptyString {
+ fn eq(&self, other: &&NonEmptyStr) -> bool {
+ PartialEq::eq(self.as_ne_str(), *other)
+ }
+
+ fn ne(&self, other: &&NonEmptyStr) -> bool {
+ PartialEq::ne(self.as_ne_str(), *other)
+ }
+}
+
+impl PartialEq<NonEmptyStr> for &NonEmptyString {
+ fn eq(&self, other: &NonEmptyStr) -> bool {
+ PartialEq::eq(self.as_ne_str(), other)
+ }
+
+ fn ne(&self, other: &NonEmptyStr) -> bool {
+ PartialEq::ne(self.as_ne_str(), other)
+ }
+}
+////////////////////////////////////////////////////////////
+
+impl Display for NonEmptyString {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ self.inner().fmt(f)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ fn cmp(nes: &NonEmptyString, s: &str) {
+ assert_eq!(nes, s);
+ //assert_eq!(s, nes);
+ assert_eq!(&nes[..], s);
+ assert_eq!(nes.as_str(), s);
+ assert_eq!(nes.as_ne_str(), s);
+ assert_eq!(nes.deref(), s);
+ assert_eq!(nes.inner(), s);
+ }
+
+ #[test]
+ fn non_empty_string() {
+ let foo = "foo";
+ let foo_str = foo.to_owned();
+ let ne_foo = NonEmptyStr::new(foo).unwrap();
+
+ // `new()` from non-empty string
+ let ne_foo_str = NonEmptyString::new(foo_str.clone()).unwrap();
+ cmp(&ne_foo_str, foo);
+
+ assert_eq!(ne_foo_str, ne_foo_str);
+ assert_eq!(ne_foo_str, &ne_foo_str);
+ assert_eq!(&ne_foo_str, ne_foo_str);
+ assert_eq!(&ne_foo_str, &ne_foo_str);
+ assert_eq!(ne_foo_str, *ne_foo_str);
+ assert_eq!(*ne_foo_str, ne_foo_str);
+ assert_eq!(*ne_foo_str, *ne_foo_str);
+
+ // `new()` from empty string
+ let empty = "";
+ assert!(NonEmptyString::new(empty.to_owned()).is_none());
+
+ // `unchecked_new()` from non-empty string
+ {
+ let ne_foo_str = unsafe { NonEmptyString::new_unchecked(foo_str.clone()) };
+ cmp(&ne_foo_str, foo);
+ }
+
+ // from `NonEmptyStr`.
+ {
+ let ne_foo_str: NonEmptyString = ne_foo.into();
+ cmp(&ne_foo_str, foo);
+
+ let ne_foo_str = <NonEmptyString as From<&NonEmptyStr>>::from(&ne_foo);
+ cmp(&ne_foo_str, foo);
+ }
+
+ // try from non-empty slice
+ {
+ use std::convert::TryInto;
+
+ let ne_foo_str: NonEmptyString = foo.try_into().unwrap();
+ cmp(&ne_foo_str, foo);
+
+ let ne_foo_str = <NonEmptyString as TryFrom<&str>>::try_from(foo).unwrap();
+ cmp(&ne_foo_str, foo);
+ }
+
+ // try from empty slice
+ {
+ use std::convert::TryInto;
+
+ let ne_foo_str: Result<NonEmptyString, _> = "".try_into();
+ assert!(ne_foo_str.is_err());
+
+ let ne_foo_str = <NonEmptyString as TryFrom<&str>>::try_from("");
+ assert!(ne_foo_str.is_err());
+ }
+
+ // try from non-empty `String`
+ {
+ use std::convert::TryInto;
+
+ let ne_foo_str: NonEmptyString = foo_str.clone().try_into().unwrap();
+ cmp(&ne_foo_str, foo);
+
+ let ne_foo_str =
+ <NonEmptyString as TryFrom<String>>::try_from(foo_str.clone()).unwrap();
+ cmp(&ne_foo_str, foo);
+ }
+
+ // try from empty `String`
+ {
+ use std::convert::TryInto;
+
+ let empty_str = "".to_owned();
+
+ let ne_foo_str: Result<NonEmptyString, _> = empty_str.clone().try_into();
+ assert!(ne_foo_str.is_err());
+
+ let ne_foo_str = <NonEmptyString as TryFrom<String>>::try_from(empty_str);
+ assert!(ne_foo_str.is_err());
+ }
+ }
+
+ #[cfg(debug_assertions)]
+ #[test]
+ #[should_panic(expected = "tried to create a non-empty string from an empty source")]
+ fn new_unchecked_panic() {
+ let _ = unsafe { NonEmptyString::new_unchecked("".to_owned()) };
+ }
+}