11
11
use std:: ffi;
12
12
use std:: ops:: Deref ;
13
13
14
- const SIZE : usize = 38 ;
14
+ use smallvec:: SmallVec ;
15
+
16
+ const SIZE : usize = 36 ;
15
17
16
18
/// Like SmallVec but for C strings.
17
19
#[ derive( Clone ) ]
18
- pub enum SmallCStr {
19
- OnStack {
20
- data : [ u8 ; SIZE ] ,
21
- len_with_nul : u8 ,
22
- } ,
23
- OnHeap {
24
- data : ffi:: CString ,
25
- }
20
+ pub struct SmallCStr {
21
+ data : SmallVec < [ u8 ; SIZE ] > ,
26
22
}
27
23
28
24
impl SmallCStr {
29
25
#[ inline]
30
26
pub fn new ( s : & str ) -> SmallCStr {
31
- if s. len ( ) < SIZE {
32
- let mut data = [ 0 ; SIZE ] ;
33
- data[ .. s. len ( ) ] . copy_from_slice ( s. as_bytes ( ) ) ;
34
- let len_with_nul = s. len ( ) + 1 ;
35
-
36
- // Make sure once that this is a valid CStr
37
- if let Err ( e) = ffi:: CStr :: from_bytes_with_nul ( & data[ .. len_with_nul] ) {
38
- panic ! ( "The string \" {}\" cannot be converted into a CStr: {}" , s, e) ;
39
- }
40
-
41
- SmallCStr :: OnStack {
42
- data,
43
- len_with_nul : len_with_nul as u8 ,
44
- }
27
+ let len = s. len ( ) ;
28
+ let len1 = len + 1 ;
29
+ let data = if len < SIZE {
30
+ let mut buf = [ 0 ; SIZE ] ;
31
+ buf[ ..len] . copy_from_slice ( s. as_bytes ( ) ) ;
32
+ SmallVec :: from_buf_and_len ( buf, len1)
45
33
} else {
46
- SmallCStr :: OnHeap {
47
- data : ffi:: CString :: new ( s) . unwrap ( )
48
- }
34
+ let mut data = Vec :: with_capacity ( len1) ;
35
+ data. extend_from_slice ( s. as_bytes ( ) ) ;
36
+ data. push ( 0 ) ;
37
+ SmallVec :: from_vec ( data)
38
+ } ;
39
+ if let Err ( e) = ffi:: CStr :: from_bytes_with_nul ( & data) {
40
+ panic ! ( "The string \" {}\" cannot be converted into a CStr: {}" , s, e) ;
49
41
}
42
+ SmallCStr { data }
50
43
}
51
44
45
+ #[ inline]
46
+ pub fn new_with_nul ( s : & str ) -> SmallCStr {
47
+ let b = s. as_bytes ( ) ;
48
+ if let Err ( e) = ffi:: CStr :: from_bytes_with_nul ( b) {
49
+ panic ! ( "The string \" {}\" cannot be converted into a CStr: {}" , s, e) ;
50
+ }
51
+ SmallCStr { data : SmallVec :: from_slice ( s. as_bytes ( ) ) }
52
+ }
53
+
54
+
52
55
#[ inline]
53
56
pub fn as_c_str ( & self ) -> & ffi:: CStr {
54
- match * self {
55
- SmallCStr :: OnStack { ref data, len_with_nul } => {
56
- unsafe {
57
- let slice = & data[ .. len_with_nul as usize ] ;
58
- ffi:: CStr :: from_bytes_with_nul_unchecked ( slice)
59
- }
60
- }
61
- SmallCStr :: OnHeap { ref data } => {
62
- data. as_c_str ( )
63
- }
57
+ unsafe {
58
+ ffi:: CStr :: from_bytes_with_nul_unchecked ( & self . data [ ..] )
64
59
}
65
60
}
66
61
67
62
#[ inline]
68
63
pub fn len_with_nul ( & self ) -> usize {
69
- match * self {
70
- SmallCStr :: OnStack { len_with_nul, .. } => {
71
- len_with_nul as usize
72
- }
73
- SmallCStr :: OnHeap { ref data } => {
74
- data. as_bytes_with_nul ( ) . len ( )
75
- }
76
- }
64
+ self . data . len ( )
65
+ }
66
+
67
+ pub fn spilled ( & self ) -> bool {
68
+ self . data . spilled ( )
77
69
}
78
70
}
79
71
@@ -85,7 +77,6 @@ impl Deref for SmallCStr {
85
77
}
86
78
}
87
79
88
-
89
80
#[ test]
90
81
fn short ( ) {
91
82
const TEXT : & str = "abcd" ;
@@ -95,7 +86,7 @@ fn short() {
95
86
96
87
assert_eq ! ( scs. len_with_nul( ) , TEXT . len( ) + 1 ) ;
97
88
assert_eq ! ( scs. as_c_str( ) , reference. as_c_str( ) ) ;
98
- assert ! ( if let SmallCStr :: OnStack { .. } = scs { true } else { false } ) ;
89
+ assert ! ( ! scs. spilled ( ) ) ;
99
90
}
100
91
101
92
#[ test]
@@ -107,7 +98,7 @@ fn empty() {
107
98
108
99
assert_eq ! ( scs. len_with_nul( ) , TEXT . len( ) + 1 ) ;
109
100
assert_eq ! ( scs. as_c_str( ) , reference. as_c_str( ) ) ;
110
- assert ! ( if let SmallCStr :: OnStack { .. } = scs { true } else { false } ) ;
101
+ assert ! ( ! scs. spilled ( ) ) ;
111
102
}
112
103
113
104
#[ test]
@@ -121,7 +112,7 @@ fn long() {
121
112
122
113
assert_eq ! ( scs. len_with_nul( ) , TEXT . len( ) + 1 ) ;
123
114
assert_eq ! ( scs. as_c_str( ) , reference. as_c_str( ) ) ;
124
- assert ! ( if let SmallCStr :: OnHeap { .. } = scs { true } else { false } ) ;
115
+ assert ! ( scs. spilled ( ) ) ;
125
116
}
126
117
127
118
#[ test]
0 commit comments