1111use std:: ffi;
1212use std:: ops:: Deref ;
1313
14- const SIZE : usize = 38 ;
14+ use smallvec:: SmallVec ;
15+
16+ const SIZE : usize = 36 ;
1517
1618/// Like SmallVec but for C strings.
1719#[ 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 ] > ,
2622}
2723
2824impl SmallCStr {
2925 #[ inline]
3026 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)
4533 } 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) ;
4941 }
42+ SmallCStr { data }
5043 }
5144
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+
5255 #[ inline]
5356 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 [ ..] )
6459 }
6560 }
6661
6762 #[ inline]
6863 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 ( )
7769 }
7870}
7971
@@ -85,7 +77,6 @@ impl Deref for SmallCStr {
8577 }
8678}
8779
88-
8980#[ test]
9081fn short ( ) {
9182 const TEXT : & str = "abcd" ;
@@ -95,7 +86,7 @@ fn short() {
9586
9687 assert_eq ! ( scs. len_with_nul( ) , TEXT . len( ) + 1 ) ;
9788 assert_eq ! ( scs. as_c_str( ) , reference. as_c_str( ) ) ;
98- assert ! ( if let SmallCStr :: OnStack { .. } = scs { true } else { false } ) ;
89+ assert ! ( ! scs. spilled ( ) ) ;
9990}
10091
10192#[ test]
@@ -107,7 +98,7 @@ fn empty() {
10798
10899 assert_eq ! ( scs. len_with_nul( ) , TEXT . len( ) + 1 ) ;
109100 assert_eq ! ( scs. as_c_str( ) , reference. as_c_str( ) ) ;
110- assert ! ( if let SmallCStr :: OnStack { .. } = scs { true } else { false } ) ;
101+ assert ! ( ! scs. spilled ( ) ) ;
111102}
112103
113104#[ test]
@@ -121,7 +112,7 @@ fn long() {
121112
122113 assert_eq ! ( scs. len_with_nul( ) , TEXT . len( ) + 1 ) ;
123114 assert_eq ! ( scs. as_c_str( ) , reference. as_c_str( ) ) ;
124- assert ! ( if let SmallCStr :: OnHeap { .. } = scs { true } else { false } ) ;
115+ assert ! ( scs. spilled ( ) ) ;
125116}
126117
127118#[ test]
0 commit comments