Skip to content

Commit 5d968b6

Browse files
authored
Merge pull request #187 from madsmtm/encoding-cleanup
Add `Encoding::Atomic` and refactor encoding code
2 parents 5e44539 + ffcfd4e commit 5d968b6

12 files changed

+662
-347
lines changed

objc2-encode/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ 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 `Encoding::Atomic`.
11+
* Implement `Encode` and `RefEncode` for `std::sync::atomic` types.
12+
913
### Changed
1014
* **BREAKING**: Renamed `Encoding::C_U_LONG` to `Encoding::C_ULONG`.
1115

objc2-encode/src/encode.rs

+94-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use core::num::{
55
NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
66
};
77
use core::ptr::NonNull;
8+
use core::sync::atomic;
89

910
use crate::Encoding;
1011

@@ -168,6 +169,9 @@ encode_impls!(
168169
u64 => ULongLong,
169170
f32 => Float,
170171
f64 => Double,
172+
173+
// TODO: i128 & u128
174+
// https://github.com/rust-lang/rust/issues/54341
171175
);
172176

173177
// TODO: Structs in core::arch?
@@ -285,8 +289,72 @@ encode_impls_nonzero!(
285289
NonZeroUsize => usize,
286290
);
287291

288-
// Note: I'm not sure atomic integers would be safe, since they might need the
289-
// Objective-C runtime to insert proper memory fences and ordering stuff?
292+
/// Simple helper for implementing for atomic types.
293+
macro_rules! encode_atomic_impls {
294+
($(
295+
$(#[$m:meta])*
296+
$atomic:ident => $type:ty,
297+
)*) => ($(
298+
// SAFETY: C11 `_Atomic` types use compatible synchronization
299+
// primitives, and the atomic type is guaranteed to have the same
300+
// in-memory representation as the underlying type.
301+
$(#[$m])*
302+
unsafe impl Encode for atomic::$atomic {
303+
const ENCODING: Encoding<'static> = Encoding::Atomic(&<$type>::ENCODING);
304+
}
305+
306+
$(#[$m])*
307+
unsafe impl RefEncode for atomic::$atomic {
308+
const ENCODING_REF: Encoding<'static> = Encoding::Pointer(&Self::ENCODING);
309+
}
310+
)*);
311+
}
312+
313+
encode_atomic_impls!(
314+
#[cfg(target_has_atomic = "8")]
315+
AtomicBool => bool,
316+
#[cfg(target_has_atomic = "8")]
317+
AtomicI8 => i8,
318+
#[cfg(target_has_atomic = "8")]
319+
AtomicU8 => u8,
320+
321+
#[cfg(target_has_atomic = "16")]
322+
AtomicI16 => i16,
323+
#[cfg(target_has_atomic = "16")]
324+
AtomicU16 => u16,
325+
326+
#[cfg(target_has_atomic = "32")]
327+
AtomicI32 => i32,
328+
#[cfg(target_has_atomic = "32")]
329+
AtomicU32 => u32,
330+
331+
#[cfg(target_has_atomic = "64")]
332+
AtomicI64 => i64,
333+
#[cfg(target_has_atomic = "64")]
334+
AtomicU64 => u64,
335+
336+
// TODO
337+
// #[cfg(target_has_atomic = "128")]
338+
// AtomicI128 => i128,
339+
// #[cfg(target_has_atomic = "128")]
340+
// AtomicU128 => u128,
341+
342+
#[cfg(target_has_atomic = "ptr")]
343+
AtomicIsize => isize,
344+
#[cfg(target_has_atomic = "ptr")]
345+
AtomicUsize => usize,
346+
);
347+
348+
// SAFETY: Guaranteed to have the same in-memory representation as `*mut T`.
349+
#[cfg(target_has_atomic = "ptr")]
350+
unsafe impl<T: RefEncode> Encode for atomic::AtomicPtr<T> {
351+
const ENCODING: Encoding<'static> = Encoding::Atomic(&T::ENCODING_REF);
352+
}
353+
354+
#[cfg(target_has_atomic = "ptr")]
355+
unsafe impl<T: RefEncode> RefEncode for atomic::AtomicPtr<T> {
356+
const ENCODING_REF: Encoding<'static> = Encoding::Pointer(&Self::ENCODING);
357+
}
290358

291359
/// [`Encode`] is implemented manually for `*const c_void`, instead of
292360
/// implementing [`RefEncode`], to discourage creating `&c_void`.
@@ -539,6 +607,7 @@ encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L);
539607

540608
#[cfg(test)]
541609
mod tests {
610+
use super::atomic::*;
542611
use super::*;
543612

544613
#[test]
@@ -568,6 +637,29 @@ mod tests {
568637
);
569638
}
570639

640+
#[test]
641+
fn test_atomic() {
642+
assert_eq!(AtomicI32::ENCODING, Encoding::Atomic(&Encoding::Int));
643+
assert_eq!(
644+
AtomicI32::ENCODING_REF,
645+
Encoding::Pointer(&Encoding::Atomic(&Encoding::Int))
646+
);
647+
assert_eq!(
648+
AtomicPtr::<i32>::ENCODING,
649+
Encoding::Atomic(&Encoding::Pointer(&Encoding::Int))
650+
);
651+
652+
assert_eq!(AtomicI8::ENCODING, Encoding::Atomic(&Encoding::Char));
653+
assert_eq!(
654+
AtomicI8::ENCODING_REF,
655+
Encoding::Pointer(&Encoding::Atomic(&Encoding::Char))
656+
);
657+
assert_eq!(
658+
AtomicPtr::<i8>::ENCODING,
659+
Encoding::Atomic(&Encoding::String)
660+
);
661+
}
662+
571663
#[test]
572664
fn test_void() {
573665
// TODO: Remove this

0 commit comments

Comments
 (0)