@@ -6,7 +6,11 @@ use core::num::{
66} ;
77use core:: ptr:: NonNull ;
88use core:: sync:: atomic;
9+ #[ cfg( feature = "std" ) ] // TODO: Use `core`
10+ use std:: ffi:: CStr ;
911
12+ use crate :: helper:: NestingLevel ;
13+ use crate :: static_str:: { static_encoding_str_array, static_encoding_str_len} ;
1014use crate :: Encoding ;
1115
1216/// Types that have an Objective-C type-encoding.
@@ -16,6 +20,7 @@ use crate::Encoding;
1620/// If your type is an opaque type you should not need to implement this;
1721/// there you will only need [`RefEncode`].
1822///
23+ ///
1924/// # Safety
2025///
2126/// The type must be FFI-safe, meaning a C-compatible `repr` (`repr(C)`,
@@ -33,6 +38,9 @@ use crate::Encoding;
3338/// passed to Objective-C via. `objc2::msg_send!` their destructor will not be
3439/// called!
3540///
41+ /// Finally, you must not override [`ENCODING_CSTR`][Self::ENCODING_CSTR].
42+ ///
43+ ///
3644/// # Examples
3745///
3846/// Implementing for a struct:
@@ -69,6 +77,43 @@ use crate::Encoding;
6977pub unsafe trait Encode {
7078 /// The Objective-C type-encoding for this type.
7179 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+ } ;
72117}
73118
74119/// Types whoose references has an Objective-C type-encoding.
@@ -736,4 +781,39 @@ mod tests {
736781 assert_eq ! ( <( i8 , ) >:: ENCODINGS , & [ i8 :: ENCODING ] ) ;
737782 assert_eq ! ( <( i8 , u32 ) >:: ENCODINGS , & [ i8 :: ENCODING , u32 :: ENCODING ] ) ;
738783 }
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 ; 128 ] ;
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+ }
739819}
0 commit comments