Skip to content

Commit c5ad3ce

Browse files
committed
Add static encoding strings
1 parent fdbe88f commit c5ad3ce

File tree

16 files changed

+279
-7
lines changed

16 files changed

+279
-7
lines changed

objc2-encode/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## Unreleased - YYYY-MM-DD
88

9+
### Added
10+
* Added `Encode::ENCODING_CSTR` for statically generating an encoding string.
11+
912
### Fixed
1013
* Fixed the encoding output and comparison of structs behind pointers.
1114

objc2-encode/src/encode.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ use core::num::{
66
};
77
use core::ptr::NonNull;
88
use 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};
1014
use 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;
6977
pub 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; 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+
}
739819
}

objc2-encode/src/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,6 @@ mod encode;
110110
mod encoding;
111111
mod helper;
112112
mod parse;
113-
114-
// Will be used at some point when generic constants are available
115-
#[allow(dead_code)]
116113
mod static_str;
117114

118115
pub use self::encode::{Encode, EncodeArguments, RefEncode};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[package]
2+
name = "test_encoding_cstr"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[lib]
8+
path = "lib.rs"
9+
10+
[dependencies]
11+
objc2-encode = { path = "../../../objc2-encode", default-features = false }
12+
13+
[features]
14+
default = ["apple", "std"]
15+
std = ["objc2-encode/std"]
16+
17+
# Runtime
18+
apple = []
19+
gnustep-1-7 = []
20+
gnustep-1-8 = ["gnustep-1-7"]
21+
gnustep-1-9 = ["gnustep-1-8"]
22+
gnustep-2-0 = ["gnustep-1-9"]
23+
gnustep-2-1 = ["gnustep-2-0"]
24+
25+
# Hack
26+
assembly-features = ["std"]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.section __TEXT,__text,regular,pure_instructions
2+
.section __TEXT,__const
3+
l_anon.a88231c846af3b75605317c1ca346ede.0:
4+
.asciz "c\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
5+
6+
.section __DATA,__const
7+
.globl _ENC
8+
.p2align 3
9+
_ENC:
10+
.quad l_anon.a88231c846af3b75605317c1ca346ede.0
11+
.asciz "\002\000\000\000\000\000\000"
12+
13+
.subsections_via_symbols
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.section __TEXT,__text,regular,pure_instructions
2+
.syntax unified
3+
.section __TEXT,__const
4+
l_anon.a88231c846af3b75605317c1ca346ede.0:
5+
.asciz "c\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
6+
7+
.section __DATA,__const
8+
.globl _ENC
9+
.p2align 2
10+
_ENC:
11+
.long l_anon.a88231c846af3b75605317c1ca346ede.0
12+
.asciz "\002\000\000"
13+
14+
.subsections_via_symbols
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.section __TEXT,__text,regular,pure_instructions
2+
.syntax unified
3+
.section __TEXT,__const
4+
l_anon.a88231c846af3b75605317c1ca346ede.0:
5+
.asciz "c\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
6+
7+
.section __DATA,__const
8+
.globl _ENC
9+
.p2align 2
10+
_ENC:
11+
.long l_anon.a88231c846af3b75605317c1ca346ede.0
12+
.asciz "\002\000\000"
13+
14+
.subsections_via_symbols
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.section __TEXT,__text,regular,pure_instructions
2+
.intel_syntax noprefix
3+
.section __TEXT,__const
4+
l_anon.a88231c846af3b75605317c1ca346ede.0:
5+
.asciz "c\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
6+
7+
.section __DATA,__const
8+
.globl _ENC
9+
.p2align 2
10+
_ENC:
11+
.long l_anon.a88231c846af3b75605317c1ca346ede.0
12+
.asciz "\002\000\000"
13+
14+
.subsections_via_symbols
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.section __TEXT,__text,regular,pure_instructions
2+
.intel_syntax noprefix
3+
.section __TEXT,__const
4+
l_anon.a88231c846af3b75605317c1ca346ede.0:
5+
.asciz "c\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
6+
7+
.section __DATA,__const
8+
.globl _ENC
9+
.p2align 3
10+
_ENC:
11+
.quad l_anon.a88231c846af3b75605317c1ca346ede.0
12+
.asciz "\002\000\000\000\000\000\000"
13+
14+
.subsections_via_symbols
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
.text
2+
.intel_syntax noprefix
3+
.type .Lanon.a88231c846af3b75605317c1ca346ede.0,@object
4+
.section .rodata..Lanon.a88231c846af3b75605317c1ca346ede.0,"a",@progbits
5+
.Lanon.a88231c846af3b75605317c1ca346ede.0:
6+
.asciz "c\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
7+
.size .Lanon.a88231c846af3b75605317c1ca346ede.0, 128
8+
9+
.type ENC,@object
10+
.section .data.rel.ro.ENC,"aw",@progbits
11+
.globl ENC
12+
.p2align 2
13+
ENC:
14+
.long .Lanon.a88231c846af3b75605317c1ca346ede.0
15+
.asciz "\002\000\000"
16+
.size ENC, 8
17+
18+
.section ".note.GNU-stack","",@progbits

0 commit comments

Comments
 (0)