@@ -9,16 +9,17 @@ mod test_readme {
99 #[ doc = include_str ! ( "../README.md" ) ]
1010 mod something { }
1111}
12-
13- use delegate:: delegate;
14- use std:: fmt:: Display ;
15-
12+ mod error;
1613#[ cfg( feature = "serde" ) ]
1714mod serde_support;
1815
16+ use delegate:: delegate;
17+ pub use error:: EmptyString ;
18+ use std:: { fmt:: Display , str:: FromStr } ;
19+
1920/// A simple String wrapper type, similar to NonZeroUsize and friends.
2021/// Guarantees that the String contained inside is not of length 0.
21- #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
22+ #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
2223#[ repr( transparent) ]
2324pub struct NonEmptyString ( String ) ;
2425
@@ -48,34 +49,34 @@ impl NonEmptyString {
4849 delegate ! {
4950 to self . 0 {
5051 /// Is forwarded to the inner String.
51- /// See [`std::string:: String::into_bytes`]
52+ /// See [`String::into_bytes`]
5253 pub fn into_bytes( self ) -> Vec <u8 >;
5354
5455 /// Is forwarded to the inner String.
55- /// See [`std::string:: String::as_str`]
56+ /// See [`String::as_str`]
5657 pub fn as_str( & self ) -> & str ;
5758
5859 /// Is forwarded to the inner String.
59- /// See [`std::string:: String::push_str`]
60+ /// See [`String::push_str`]
6061 pub fn push_str( & mut self , string: & str ) ;
6162
6263 /// Is forwarded to the inner String.
63- /// See [`std::string:: String::capacity`]
64+ /// See [`String::capacity`]
6465 pub fn capacity( & self ) -> usize ;
6566
6667 /// Is forwarded to the inner String.
67- /// See [`std::string:: String::reserve`]
68+ /// See [`String::reserve`]
6869 pub fn reserve( & mut self , additional: usize ) ;
6970
7071 /// Is forwarded to the inner String.
71- /// See [`std::string:: String::reserve_exact`]
72+ /// See [`String::reserve_exact`]
7273 pub fn reserve_exact( & mut self , additional: usize ) ;
7374
7475 // For some reason we cannot delegate the following:
7576 // pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>
7677
7778 /// Is forwarded to the inner String.
78- /// See [`std::string:: String::try_reserve_exact`]
79+ /// See [`String::try_reserve_exact`]
7980 pub fn try_reserve_exact(
8081 & mut self ,
8182 additional: usize
@@ -86,31 +87,31 @@ impl NonEmptyString {
8687 pub fn shrink_to_fit( & mut self ) ;
8788
8889 /// Is forwarded to the inner String.
89- /// See [`std::string:: String::shrink_to`]
90+ /// See [`String::shrink_to`]
9091 pub fn shrink_to( & mut self , min_capacity: usize ) ;
9192
9293 /// Is forwarded to the inner String.
93- /// See [`std::string:: String::push`]
94+ /// See [`String::push`]
9495 pub fn push( & mut self , ch: char ) ;
9596
9697 /// Is forwarded to the inner String.
97- /// See [`std::string:: String::as_bytes`]
98+ /// See [`String::as_bytes`]
9899 pub fn as_bytes( & self ) -> & [ u8 ] ;
99100
100101 /// Is forwarded to the inner String.
101- /// See [`std::string:: String::insert`]
102+ /// See [`String::insert`]
102103 pub fn insert( & mut self , idx: usize , ch: char ) ;
103104
104105 /// Is forwarded to the inner String.
105- /// See [`std::string:: String::insert_str`]
106+ /// See [`String::insert_str`]
106107 pub fn insert_str( & mut self , idx: usize , string: & str ) ;
107108
108109 /// Is forwarded to the inner String.
109- /// See [`std::string:: String::len`]
110+ /// See [`String::len`]
110111 pub fn len( & self ) -> usize ;
111112
112113 /// Is forwarded to the inner String.
113- /// See [`std::string:: String::into_boxed_str`]
114+ /// See [`String::into_boxed_str`]
114115 pub fn into_boxed_str( self ) -> Box <str >;
115116 }
116117 }
@@ -154,8 +155,29 @@ impl Display for NonEmptyString {
154155 }
155156}
156157
158+ impl FromStr for NonEmptyString {
159+ type Err = EmptyString ;
160+
161+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
162+ if s. is_empty ( ) {
163+ return Err ( EmptyString ) ;
164+ }
165+
166+ Ok ( Self ( s. to_string ( ) ) )
167+ }
168+ }
169+
170+ impl From < NonEmptyString > for String {
171+ fn from ( value : NonEmptyString ) -> Self {
172+ value. 0
173+ }
174+ }
175+
157176#[ cfg( test) ]
158177mod tests {
178+ use std:: collections:: HashMap ;
179+ use std:: collections:: HashSet ;
180+
159181 use super :: * ;
160182
161183 #[ test]
@@ -205,4 +227,39 @@ mod tests {
205227 println ! ( "{}" , & str ) ;
206228 assert_eq ! ( String :: from( "string" ) , str . to_string( ) )
207229 }
230+
231+ #[ test]
232+ fn from_str_works ( ) {
233+ let valid_str = "string" ;
234+
235+ let _non_empty_string = NonEmptyString :: from_str ( "" ) . expect_err ( "operation must be failed" ) ;
236+
237+ let non_empty_string = NonEmptyString :: from_str ( valid_str) . unwrap ( ) ;
238+ assert_eq ! ( non_empty_string. as_str( ) , valid_str) ;
239+ assert_eq ! ( non_empty_string, valid_str. parse( ) . unwrap( ) ) ;
240+ }
241+
242+ #[ test]
243+ fn into_works ( ) {
244+ let non_empty_string = NonEmptyString :: new ( "string" . to_string ( ) ) . unwrap ( ) ;
245+ let _string: String = non_empty_string. into ( ) ;
246+
247+ let non_empty_string = NonEmptyString :: new ( "string" . to_string ( ) ) . unwrap ( ) ;
248+ let _string = String :: from ( non_empty_string) ;
249+ }
250+
251+ #[ test]
252+ fn hash_works ( ) {
253+ let mut map = HashMap :: new ( ) ;
254+ map. insert ( NonEmptyString :: from_str ( "id.1" ) . unwrap ( ) , 1 ) ;
255+ map. insert ( NonEmptyString :: from_str ( "id.2" ) . unwrap ( ) , 2 ) ;
256+
257+ assert_eq ! ( map. len( ) , 2 ) ;
258+
259+ let mut set = HashSet :: new ( ) ;
260+ set. insert ( NonEmptyString :: from_str ( "1" ) . unwrap ( ) ) ;
261+ set. insert ( NonEmptyString :: from_str ( "2" ) . unwrap ( ) ) ;
262+
263+ assert_eq ! ( set. len( ) , 2 ) ;
264+ }
208265}
0 commit comments