@@ -9,16 +9,17 @@ mod test_readme {
9
9
#[ doc = include_str ! ( "../README.md" ) ]
10
10
mod something { }
11
11
}
12
-
13
- use delegate:: delegate;
14
- use std:: fmt:: Display ;
15
-
12
+ mod error;
16
13
#[ cfg( feature = "serde" ) ]
17
14
mod serde_support;
18
15
16
+ use delegate:: delegate;
17
+ pub use error:: EmptyString ;
18
+ use std:: { fmt:: Display , str:: FromStr } ;
19
+
19
20
/// A simple String wrapper type, similar to NonZeroUsize and friends.
20
21
/// 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 ) ]
22
23
#[ repr( transparent) ]
23
24
pub struct NonEmptyString ( String ) ;
24
25
@@ -48,34 +49,34 @@ impl NonEmptyString {
48
49
delegate ! {
49
50
to self . 0 {
50
51
/// Is forwarded to the inner String.
51
- /// See [`std::string:: String::into_bytes`]
52
+ /// See [`String::into_bytes`]
52
53
pub fn into_bytes( self ) -> Vec <u8 >;
53
54
54
55
/// Is forwarded to the inner String.
55
- /// See [`std::string:: String::as_str`]
56
+ /// See [`String::as_str`]
56
57
pub fn as_str( & self ) -> & str ;
57
58
58
59
/// Is forwarded to the inner String.
59
- /// See [`std::string:: String::push_str`]
60
+ /// See [`String::push_str`]
60
61
pub fn push_str( & mut self , string: & str ) ;
61
62
62
63
/// Is forwarded to the inner String.
63
- /// See [`std::string:: String::capacity`]
64
+ /// See [`String::capacity`]
64
65
pub fn capacity( & self ) -> usize ;
65
66
66
67
/// Is forwarded to the inner String.
67
- /// See [`std::string:: String::reserve`]
68
+ /// See [`String::reserve`]
68
69
pub fn reserve( & mut self , additional: usize ) ;
69
70
70
71
/// Is forwarded to the inner String.
71
- /// See [`std::string:: String::reserve_exact`]
72
+ /// See [`String::reserve_exact`]
72
73
pub fn reserve_exact( & mut self , additional: usize ) ;
73
74
74
75
// For some reason we cannot delegate the following:
75
76
// pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>
76
77
77
78
/// Is forwarded to the inner String.
78
- /// See [`std::string:: String::try_reserve_exact`]
79
+ /// See [`String::try_reserve_exact`]
79
80
pub fn try_reserve_exact(
80
81
& mut self ,
81
82
additional: usize
@@ -86,31 +87,31 @@ impl NonEmptyString {
86
87
pub fn shrink_to_fit( & mut self ) ;
87
88
88
89
/// Is forwarded to the inner String.
89
- /// See [`std::string:: String::shrink_to`]
90
+ /// See [`String::shrink_to`]
90
91
pub fn shrink_to( & mut self , min_capacity: usize ) ;
91
92
92
93
/// Is forwarded to the inner String.
93
- /// See [`std::string:: String::push`]
94
+ /// See [`String::push`]
94
95
pub fn push( & mut self , ch: char ) ;
95
96
96
97
/// Is forwarded to the inner String.
97
- /// See [`std::string:: String::as_bytes`]
98
+ /// See [`String::as_bytes`]
98
99
pub fn as_bytes( & self ) -> & [ u8 ] ;
99
100
100
101
/// Is forwarded to the inner String.
101
- /// See [`std::string:: String::insert`]
102
+ /// See [`String::insert`]
102
103
pub fn insert( & mut self , idx: usize , ch: char ) ;
103
104
104
105
/// Is forwarded to the inner String.
105
- /// See [`std::string:: String::insert_str`]
106
+ /// See [`String::insert_str`]
106
107
pub fn insert_str( & mut self , idx: usize , string: & str ) ;
107
108
108
109
/// Is forwarded to the inner String.
109
- /// See [`std::string:: String::len`]
110
+ /// See [`String::len`]
110
111
pub fn len( & self ) -> usize ;
111
112
112
113
/// Is forwarded to the inner String.
113
- /// See [`std::string:: String::into_boxed_str`]
114
+ /// See [`String::into_boxed_str`]
114
115
pub fn into_boxed_str( self ) -> Box <str >;
115
116
}
116
117
}
@@ -154,8 +155,29 @@ impl Display for NonEmptyString {
154
155
}
155
156
}
156
157
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
+
157
176
#[ cfg( test) ]
158
177
mod tests {
178
+ use std:: collections:: HashMap ;
179
+ use std:: collections:: HashSet ;
180
+
159
181
use super :: * ;
160
182
161
183
#[ test]
@@ -205,4 +227,39 @@ mod tests {
205
227
println ! ( "{}" , & str ) ;
206
228
assert_eq ! ( String :: from( "string" ) , str . to_string( ) )
207
229
}
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
+ }
208
265
}
0 commit comments