@@ -6,7 +6,11 @@ use core::num::{
6
6
} ;
7
7
use core:: ptr:: NonNull ;
8
8
use core:: sync:: atomic;
9
+ #[ cfg( feature = "std" ) ] // TODO: Use `core`
10
+ use std:: ffi:: CStr ;
9
11
12
+ use crate :: helper:: NestingLevel ;
13
+ use crate :: static_str:: { static_encoding_str_array, static_encoding_str_len} ;
10
14
use crate :: Encoding ;
11
15
12
16
/// Types that have an Objective-C type-encoding.
@@ -16,6 +20,7 @@ use crate::Encoding;
16
20
/// If your type is an opaque type you should not need to implement this;
17
21
/// there you will only need [`RefEncode`].
18
22
///
23
+ ///
19
24
/// # Safety
20
25
///
21
26
/// The type must be FFI-safe, meaning a C-compatible `repr` (`repr(C)`,
@@ -33,6 +38,9 @@ use crate::Encoding;
33
38
/// passed to Objective-C via. `objc2::msg_send!` their destructor will not be
34
39
/// called!
35
40
///
41
+ /// Finally, you must not override [`ENCODING_CSTR`][Self::ENCODING_CSTR].
42
+ ///
43
+ ///
36
44
/// # Examples
37
45
///
38
46
/// Implementing for a struct:
@@ -69,6 +77,43 @@ use crate::Encoding;
69
77
pub unsafe trait Encode {
70
78
/// The Objective-C type-encoding for this type.
71
79
const ENCODING : Encoding < ' static > ;
80
+
81
+ #[ doc( hidden) ]
82
+ const __ENCODING_CSTR_LEN: usize = static_encoding_str_len ( Self :: ENCODING , NestingLevel :: new ( ) ) ;
83
+
84
+ #[ doc( hidden) ]
85
+ const __ENCODING_CSTR_ARRAY: [ u8 ; 128 ] = {
86
+ if Self :: __ENCODING_CSTR_LEN >= 127 {
87
+ panic ! ( "encoding string was too long! The maximum supported length is 1023." ) ;
88
+ }
89
+
90
+ static_encoding_str_array ( Self :: ENCODING , NestingLevel :: new ( ) )
91
+ } ;
92
+
93
+ /// The encoding as a static [`CStr`].
94
+ ///
95
+ /// This has the same output as `Encoding::to_string`, but it is created
96
+ /// at compile-time instead.
97
+ ///
98
+ /// The encoding is guaranteed to be a pure ASCII string.
99
+ #[ cfg( feature = "std" ) ]
100
+ const ENCODING_CSTR : & ' static CStr = {
101
+ let mut slice: & [ u8 ] = & Self :: __ENCODING_CSTR_ARRAY;
102
+ // Cut down to desired size (length + 1 for NUL byte)
103
+ // Equivalent to:
104
+ // slice[0..Self::__ENCODING_CSTR_LEN + 1]
105
+ while slice. len ( ) > Self :: __ENCODING_CSTR_LEN + 1 {
106
+ if let Some ( res) = slice. split_last ( ) {
107
+ slice = res. 1 ;
108
+ } else {
109
+ unreachable ! ( ) ;
110
+ }
111
+ }
112
+ // SAFETY: `static_encoding_str_array` is guaranteed to not contain
113
+ // any NULL bytes (the only place those could appear would be in a
114
+ // struct or union name, and that case is checked).
115
+ unsafe { CStr :: from_bytes_with_nul_unchecked ( slice) }
116
+ } ;
72
117
}
73
118
74
119
/// Types whoose references has an Objective-C type-encoding.
@@ -736,4 +781,39 @@ mod tests {
736
781
assert_eq ! ( <( i8 , ) >:: ENCODINGS , & [ i8 :: ENCODING ] ) ;
737
782
assert_eq ! ( <( i8 , u32 ) >:: ENCODINGS , & [ i8 :: ENCODING , u32 :: ENCODING ] ) ;
738
783
}
784
+
785
+ #[ test]
786
+ #[ cfg( feature = "std" ) ]
787
+ fn test_cstr_simple ( ) {
788
+ assert_eq ! ( i8 :: __ENCODING_CSTR_LEN, 1 ) ;
789
+
790
+ let mut array = [ 0 ; 1024 ] ;
791
+ array[ 0 ] = b'c' ;
792
+ assert_eq ! ( i8 :: __ENCODING_CSTR_ARRAY, array) ;
793
+
794
+ let cstr = CStr :: from_bytes_with_nul ( b"c\0 " ) . unwrap ( ) ;
795
+ assert_eq ! ( i8 :: ENCODING_CSTR , cstr) ;
796
+ }
797
+
798
+ #[ test]
799
+ #[ cfg( feature = "std" ) ]
800
+ fn test_cstr ( ) {
801
+ struct X ;
802
+
803
+ unsafe impl Encode for X {
804
+ const ENCODING : Encoding < ' static > = Encoding :: Struct (
805
+ "abc" ,
806
+ & [
807
+ Encoding :: Union ( "def" , & [ Encoding :: Char ] ) ,
808
+ <* const * const i8 >:: ENCODING ,
809
+ <AtomicPtr < AtomicI16 > >:: ENCODING ,
810
+ <extern "C" fn ( ) >:: ENCODING ,
811
+ ] ,
812
+ ) ;
813
+ }
814
+
815
+ let s = b"{abc=(def=c)^*A^As^?}\0 " ;
816
+
817
+ assert_eq ! ( X :: ENCODING_CSTR . to_bytes_with_nul( ) , s) ;
818
+ }
739
819
}
0 commit comments