1#![cfg_attr(not(all(test, feature = "float")), allow(dead_code, unused_macros))]
4
5#[macro_use]
6#[path = "gen/utils.rs"]
7mod generated;
8
9use core::sync::atomic::Ordering;
10
11macro_rules! static_assert {
12 ($cond:expr $(,)?) => {{
13 let [] = [(); true as usize - $crate::utils::_assert_is_bool($cond) as usize];
14 }};
15}
16pub(crate) const fn _assert_is_bool(v: bool) -> bool {
17 v
18}
19
20macro_rules! static_assert_layout {
21 ($atomic_type:ty, $value_type:ty) => {
22 static_assert!(
23 core::mem::align_of::<$atomic_type>() == core::mem::size_of::<$atomic_type>()
24 );
25 static_assert!(core::mem::size_of::<$atomic_type>() == core::mem::size_of::<$value_type>());
26 };
27}
28
29macro_rules! doc_comment {
31 ($doc:expr, $($tt:tt)*) => {
32 #[doc = $doc]
33 $($tt)*
34 };
35}
36
37#[allow(unused_macros)]
46#[cfg(not(portable_atomic_no_outline_atomics))]
47#[cfg(any(
48 target_arch = "aarch64",
49 target_arch = "arm",
50 target_arch = "arm64ec",
51 target_arch = "powerpc64",
52 target_arch = "riscv32",
53 target_arch = "riscv64",
54 all(target_arch = "x86_64", not(any(target_env = "sgx", miri))),
55))]
56macro_rules! ifunc {
57 (unsafe fn($($arg_pat:ident: $arg_ty:ty),*) $(-> $ret_ty:ty)? { $($detect_body:tt)* }) => {{
58 type FnTy = unsafe fn($($arg_ty),*) $(-> $ret_ty)?;
59 static FUNC: core::sync::atomic::AtomicPtr<()>
60 = core::sync::atomic::AtomicPtr::new(detect as *mut ());
61 #[cold]
62 unsafe fn detect($($arg_pat: $arg_ty),*) $(-> $ret_ty)? {
63 let func: FnTy = { $($detect_body)* };
64 FUNC.store(func as *mut (), core::sync::atomic::Ordering::Relaxed);
65 unsafe { func($($arg_pat),*) }
67 }
68 let func = {
72 core::mem::transmute::<*mut (), FnTy>(FUNC.load(core::sync::atomic::Ordering::Relaxed))
73 };
74 func($($arg_pat),*)
78 }};
79}
80
81#[allow(unused_macros)]
82#[cfg(not(portable_atomic_no_outline_atomics))]
83#[cfg(any(
84 target_arch = "aarch64",
85 target_arch = "arm",
86 target_arch = "arm64ec",
87 target_arch = "powerpc64",
88 target_arch = "riscv32",
89 target_arch = "riscv64",
90 all(target_arch = "x86_64", not(any(target_env = "sgx", miri))),
91))]
92macro_rules! fn_alias {
93 (
94 $(#[$($fn_attr:tt)*])*
95 $vis:vis unsafe fn($($arg_pat:ident: $arg_ty:ty),*) $(-> $ret_ty:ty)?;
96 $(#[$($alias_attr:tt)*])*
97 $new:ident = $from:ident($($last_args:tt)*);
98 $($rest:tt)*
99 ) => {
100 $(#[$($fn_attr)*])*
101 $(#[$($alias_attr)*])*
102 $vis unsafe fn $new($($arg_pat: $arg_ty),*) $(-> $ret_ty)? {
103 unsafe { $from($($arg_pat,)* $($last_args)*) }
105 }
106 fn_alias! {
107 $(#[$($fn_attr)*])*
108 $vis unsafe fn($($arg_pat: $arg_ty),*) $(-> $ret_ty)?;
109 $($rest)*
110 }
111 };
112 (
113 $(#[$($attr:tt)*])*
114 $vis:vis unsafe fn($($arg_pat:ident: $arg_ty:ty),*) $(-> $ret_ty:ty)?;
115 ) => {}
116}
117
118macro_rules! const_fn {
120 (
121 const_if: #[cfg($($cfg:tt)+)];
122 $(#[$($attr:tt)*])*
123 $vis:vis const $($rest:tt)*
124 ) => {
125 #[cfg($($cfg)+)]
126 $(#[$($attr)*])*
127 $vis const $($rest)*
128 #[cfg(not($($cfg)+))]
129 $(#[$($attr)*])*
130 $vis $($rest)*
131 };
132}
133
134macro_rules! impl_debug_and_serde {
137 (AtomicF16) => {
139 impl_debug!(AtomicF16);
140 };
141 (AtomicF128) => {
142 impl_debug!(AtomicF128);
143 };
144 ($atomic_type:ident) => {
145 impl_debug!($atomic_type);
146 #[cfg(feature = "serde")]
147 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
148 impl serde::ser::Serialize for $atomic_type {
149 #[allow(clippy::missing_inline_in_public_items)] fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
151 where
152 S: serde::ser::Serializer,
153 {
154 self.load(Ordering::Relaxed).serialize(serializer)
156 }
157 }
158 #[cfg(feature = "serde")]
159 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
160 impl<'de> serde::de::Deserialize<'de> for $atomic_type {
161 #[allow(clippy::missing_inline_in_public_items)] fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
163 where
164 D: serde::de::Deserializer<'de>,
165 {
166 serde::de::Deserialize::deserialize(deserializer).map(Self::new)
167 }
168 }
169 };
170}
171macro_rules! impl_debug {
172 ($atomic_type:ident) => {
173 impl fmt::Debug for $atomic_type {
174 #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 fmt::Debug::fmt(&self.load(Ordering::Relaxed), f)
178 }
179 }
180 };
181}
182
183macro_rules! impl_default_no_fetch_ops {
186 ($atomic_type:ident, bool) => {
187 impl $atomic_type {
188 #[inline]
189 #[cfg_attr(miri, track_caller)] pub(crate) fn and(&self, val: bool, order: Ordering) {
191 self.fetch_and(val, order);
192 }
193 #[inline]
194 #[cfg_attr(miri, track_caller)] pub(crate) fn or(&self, val: bool, order: Ordering) {
196 self.fetch_or(val, order);
197 }
198 #[inline]
199 #[cfg_attr(miri, track_caller)] pub(crate) fn xor(&self, val: bool, order: Ordering) {
201 self.fetch_xor(val, order);
202 }
203 }
204 };
205 ($atomic_type:ident, $int_type:ty) => {
206 impl $atomic_type {
207 #[inline]
208 #[cfg_attr(miri, track_caller)] pub(crate) fn add(&self, val: $int_type, order: Ordering) {
210 self.fetch_add(val, order);
211 }
212 #[inline]
213 #[cfg_attr(miri, track_caller)] pub(crate) fn sub(&self, val: $int_type, order: Ordering) {
215 self.fetch_sub(val, order);
216 }
217 #[inline]
218 #[cfg_attr(miri, track_caller)] pub(crate) fn and(&self, val: $int_type, order: Ordering) {
220 self.fetch_and(val, order);
221 }
222 #[inline]
223 #[cfg_attr(miri, track_caller)] pub(crate) fn or(&self, val: $int_type, order: Ordering) {
225 self.fetch_or(val, order);
226 }
227 #[inline]
228 #[cfg_attr(miri, track_caller)] pub(crate) fn xor(&self, val: $int_type, order: Ordering) {
230 self.fetch_xor(val, order);
231 }
232 }
233 };
234}
235macro_rules! impl_default_bit_opts {
236 ($atomic_type:ident, $int_type:ty) => {
237 impl $atomic_type {
238 #[inline]
239 #[cfg_attr(miri, track_caller)] pub(crate) fn bit_set(&self, bit: u32, order: Ordering) -> bool {
241 let mask = <$int_type>::wrapping_shl(1, bit);
242 self.fetch_or(mask, order) & mask != 0
243 }
244 #[inline]
245 #[cfg_attr(miri, track_caller)] pub(crate) fn bit_clear(&self, bit: u32, order: Ordering) -> bool {
247 let mask = <$int_type>::wrapping_shl(1, bit);
248 self.fetch_and(!mask, order) & mask != 0
249 }
250 #[inline]
251 #[cfg_attr(miri, track_caller)] pub(crate) fn bit_toggle(&self, bit: u32, order: Ordering) -> bool {
253 let mask = <$int_type>::wrapping_shl(1, bit);
254 self.fetch_xor(mask, order) & mask != 0
255 }
256 }
257 };
258}
259
260macro_rules! items {
262 ($($tt:tt)*) => {
263 $($tt)*
264 };
265}
266
267#[allow(dead_code)]
268#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
269#[inline(always)]
272#[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
273pub(crate) unsafe fn assert_unchecked(cond: bool) {
274 if !cond {
275 if cfg!(debug_assertions) {
276 unreachable!()
277 } else {
278 unsafe { core::hint::unreachable_unchecked() }
280 }
281 }
282}
283
284#[inline]
286#[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
287pub(crate) fn assert_load_ordering(order: Ordering) {
288 match order {
289 Ordering::Acquire | Ordering::Relaxed | Ordering::SeqCst => {}
290 Ordering::Release => panic!("there is no such thing as a release load"),
291 Ordering::AcqRel => panic!("there is no such thing as an acquire-release load"),
292 _ => unreachable!(),
293 }
294}
295#[inline]
297#[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
298pub(crate) fn assert_store_ordering(order: Ordering) {
299 match order {
300 Ordering::Release | Ordering::Relaxed | Ordering::SeqCst => {}
301 Ordering::Acquire => panic!("there is no such thing as an acquire store"),
302 Ordering::AcqRel => panic!("there is no such thing as an acquire-release store"),
303 _ => unreachable!(),
304 }
305}
306#[inline]
308#[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
309pub(crate) fn assert_compare_exchange_ordering(success: Ordering, failure: Ordering) {
310 match success {
311 Ordering::AcqRel
312 | Ordering::Acquire
313 | Ordering::Relaxed
314 | Ordering::Release
315 | Ordering::SeqCst => {}
316 _ => unreachable!(),
317 }
318 match failure {
319 Ordering::Acquire | Ordering::Relaxed | Ordering::SeqCst => {}
320 Ordering::Release => panic!("there is no such thing as a release failure ordering"),
321 Ordering::AcqRel => panic!("there is no such thing as an acquire-release failure ordering"),
322 _ => unreachable!(),
323 }
324}
325
326#[allow(dead_code)]
329#[inline]
330pub(crate) fn upgrade_success_ordering(success: Ordering, failure: Ordering) -> Ordering {
331 match (success, failure) {
332 (Ordering::Relaxed, Ordering::Acquire) => Ordering::Acquire,
333 (Ordering::Release, Ordering::Acquire) => Ordering::AcqRel,
334 (_, Ordering::SeqCst) => Ordering::SeqCst,
335 _ => success,
336 }
337}
338
339#[cfg(not(portable_atomic_no_asm_maybe_uninit))]
343#[cfg(target_pointer_width = "32")]
344#[allow(dead_code)]
345#[inline]
346pub(crate) fn zero_extend64_ptr(v: *mut ()) -> core::mem::MaybeUninit<u64> {
347 #[repr(C)]
348 struct ZeroExtended {
349 #[cfg(target_endian = "big")]
350 pad: *mut (),
351 v: *mut (),
352 #[cfg(target_endian = "little")]
353 pad: *mut (),
354 }
355 unsafe { core::mem::transmute(ZeroExtended { v, pad: core::ptr::null_mut() }) }
357}
358
359#[allow(dead_code)]
360#[cfg(any(
361 target_arch = "aarch64",
362 target_arch = "arm64ec",
363 target_arch = "powerpc64",
364 target_arch = "riscv64",
365 target_arch = "s390x",
366 target_arch = "x86_64",
367))]
368#[derive(Clone, Copy)]
373#[repr(C)]
374pub(crate) union U128 {
375 pub(crate) whole: u128,
376 pub(crate) pair: Pair<u64>,
377}
378#[allow(dead_code)]
379#[cfg(any(target_arch = "arm", target_arch = "riscv32"))]
380#[derive(Clone, Copy)]
385#[repr(C)]
386pub(crate) union U64 {
387 pub(crate) whole: u64,
388 pub(crate) pair: Pair<u32>,
389}
390#[allow(dead_code)]
391#[derive(Clone, Copy)]
392#[repr(C)]
393pub(crate) struct Pair<T: Copy> {
394 #[cfg(any(
396 target_endian = "little",
397 target_arch = "aarch64",
398 target_arch = "arm",
399 target_arch = "arm64ec",
400 ))]
401 pub(crate) lo: T,
402 pub(crate) hi: T,
403 #[cfg(not(any(
405 target_endian = "little",
406 target_arch = "aarch64",
407 target_arch = "arm",
408 target_arch = "arm64ec",
409 )))]
410 pub(crate) lo: T,
411}
412
413#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
414type MinWord = u32;
415#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
416type RetInt = u32;
417#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
423#[allow(dead_code)]
424#[inline]
425pub(crate) fn create_sub_word_mask_values<T>(ptr: *mut T) -> (*mut MinWord, RetInt, RetInt) {
426 #[cfg(portable_atomic_no_strict_provenance)]
427 use self::ptr::PtrExt as _;
428 use core::mem;
429 const SHIFT_MASK: bool = !cfg!(any(
436 target_arch = "bpf",
437 target_arch = "loongarch32",
438 target_arch = "loongarch64",
439 target_arch = "mips",
440 target_arch = "mips32r6",
441 target_arch = "mips64",
442 target_arch = "mips64r6",
443 target_arch = "riscv32",
444 target_arch = "riscv64",
445 target_arch = "s390x",
446 target_arch = "sparc",
447 target_arch = "sparc64",
448 target_arch = "xtensa",
449 ));
450 let ptr_mask = mem::size_of::<MinWord>() - 1;
451 let aligned_ptr = ptr.with_addr(ptr.addr() & !ptr_mask) as *mut MinWord;
452 let ptr_lsb = if SHIFT_MASK {
453 ptr.addr() & ptr_mask
454 } else {
455 ptr.addr()
457 };
458 let shift = if cfg!(any(target_endian = "little", target_arch = "s390x")) {
459 ptr_lsb.wrapping_mul(8)
460 } else {
461 (ptr_lsb ^ (mem::size_of::<MinWord>() - mem::size_of::<T>())).wrapping_mul(8)
462 };
463 let mut mask: RetInt = (1 << (mem::size_of::<T>() * 8)) - 1; if SHIFT_MASK {
465 mask <<= shift;
466 }
467 #[allow(clippy::cast_possible_truncation)]
468 {
469 (aligned_ptr, shift as RetInt, mask)
470 }
471}
472
473#[allow(dead_code)]
475pub(crate) mod ptr {
476 #[cfg(portable_atomic_no_strict_provenance)]
477 use core::mem;
478 #[cfg(not(portable_atomic_no_strict_provenance))]
479 #[allow(unused_imports)]
480 pub(crate) use core::ptr::{with_exposed_provenance, with_exposed_provenance_mut};
481
482 #[cfg(portable_atomic_no_strict_provenance)]
483 #[inline(always)]
484 #[must_use]
485 #[cfg_attr(miri, track_caller)] pub(crate) fn with_exposed_provenance<T>(addr: usize) -> *const T {
487 addr as *const T
488 }
489 #[cfg(portable_atomic_no_strict_provenance)]
490 #[inline(always)]
491 #[must_use]
492 #[cfg_attr(miri, track_caller)] pub(crate) fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T {
494 addr as *mut T
495 }
496
497 #[cfg(portable_atomic_no_strict_provenance)]
498 pub(crate) trait PtrExt<T: ?Sized>: Copy {
499 #[must_use]
500 fn addr(self) -> usize;
501 #[must_use]
502 fn with_addr(self, addr: usize) -> Self
503 where
504 T: Sized;
505 }
506 #[cfg(portable_atomic_no_strict_provenance)]
507 impl<T: ?Sized> PtrExt<T> for *mut T {
508 #[inline(always)]
509 #[must_use]
510 fn addr(self) -> usize {
511 #[allow(clippy::transmutes_expressible_as_ptr_casts)]
517 unsafe {
518 mem::transmute(self as *mut ())
519 }
520 }
521 #[allow(clippy::cast_possible_wrap)]
522 #[inline]
523 #[must_use]
524 fn with_addr(self, addr: usize) -> Self
525 where
526 T: Sized,
527 {
528 let self_addr = self.addr() as isize;
532 let dest_addr = addr as isize;
533 let offset = dest_addr.wrapping_sub(self_addr);
534 (self as *mut u8).wrapping_offset(offset) as *mut T
535 }
536 }
537}
538
539#[cfg(any(
546 test,
547 portable_atomic_test_no_std_static_assert_ffi,
548 not(any(target_arch = "x86", target_arch = "x86_64"))
549))]
550#[cfg(any(not(portable_atomic_no_asm), portable_atomic_unstable_asm))]
551#[allow(dead_code, non_camel_case_types, unused_macros)]
552#[macro_use]
553pub(crate) mod ffi {
554 pub(crate) type c_void = core::ffi::c_void;
555 #[cfg(target_pointer_width = "16")]
558 pub(crate) type c_int = i16;
559 #[cfg(target_pointer_width = "16")]
560 pub(crate) type c_uint = u16;
561 #[cfg(not(target_pointer_width = "16"))]
562 pub(crate) type c_int = i32;
563 #[cfg(not(target_pointer_width = "16"))]
564 pub(crate) type c_uint = u32;
565 #[cfg(all(target_pointer_width = "64", not(windows)))]
568 pub(crate) type c_long = i64;
569 #[cfg(all(target_pointer_width = "64", not(windows)))]
570 pub(crate) type c_ulong = u64;
571 #[cfg(not(all(target_pointer_width = "64", not(windows))))]
572 pub(crate) type c_long = i32;
573 #[cfg(not(all(target_pointer_width = "64", not(windows))))]
574 pub(crate) type c_ulong = u32;
575 pub(crate) type c_size_t = usize;
578 #[cfg(all(
581 not(any(target_vendor = "apple", windows, target_os = "vita")),
582 any(
583 target_arch = "aarch64",
584 target_arch = "arm",
585 target_arch = "csky",
586 target_arch = "hexagon",
587 target_arch = "msp430",
588 target_arch = "powerpc",
589 target_arch = "powerpc64",
590 target_arch = "riscv32",
591 target_arch = "riscv64",
592 target_arch = "s390x",
593 target_arch = "xtensa",
594 ),
595 ))]
596 pub(crate) type c_char = u8;
597 #[cfg(not(all(
598 not(any(target_vendor = "apple", windows, target_os = "vita")),
599 any(
600 target_arch = "aarch64",
601 target_arch = "arm",
602 target_arch = "csky",
603 target_arch = "hexagon",
604 target_arch = "msp430",
605 target_arch = "powerpc",
606 target_arch = "powerpc64",
607 target_arch = "riscv32",
608 target_arch = "riscv64",
609 target_arch = "s390x",
610 target_arch = "xtensa",
611 ),
612 )))]
613 pub(crate) type c_char = i8;
614
615 #[cfg(test)]
617 const _: fn() = || {
618 let _: c_int = 0 as std::os::raw::c_int;
619 let _: c_uint = 0 as std::os::raw::c_uint;
620 let _: c_long = 0 as std::os::raw::c_long;
621 let _: c_ulong = 0 as std::os::raw::c_ulong;
622 #[cfg(unix)]
623 let _: c_size_t = 0 as libc::size_t; let _: c_char = 0 as std::os::raw::c_char;
625 };
626
627 #[repr(transparent)]
628 pub(crate) struct CStr([c_char]);
629 impl CStr {
630 #[inline]
631 #[must_use]
632 pub(crate) const fn as_ptr(&self) -> *const c_char {
633 self.0.as_ptr()
634 }
635 #[inline]
640 #[must_use]
641 pub(crate) unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
642 unsafe { &*(bytes as *const [u8] as *const CStr) }
649 }
650 #[cfg(test)]
651 #[inline]
652 #[must_use]
653 pub(crate) fn to_bytes_with_nul(&self) -> &[u8] {
654 #[allow(clippy::unnecessary_cast)] unsafe {
658 &*(&self.0 as *const [c_char] as *const [u8])
659 }
660 }
661 }
662
663 macro_rules! c {
664 ($s:expr) => {{
665 const BYTES: &[u8] = concat!($s, "\0").as_bytes();
666 const _: () = static_assert!(crate::utils::ffi::_const_is_c_str(BYTES));
667 #[allow(unused_unsafe)]
668 unsafe {
670 crate::utils::ffi::CStr::from_bytes_with_nul_unchecked(BYTES)
671 }
672 }};
673 }
674
675 #[must_use]
676 pub(crate) const fn _const_is_c_str(bytes: &[u8]) -> bool {
677 #[cfg(portable_atomic_no_track_caller)]
678 {
679 !bytes.is_empty()
689 }
690 #[cfg(not(portable_atomic_no_track_caller))]
691 {
692 if bytes.is_empty() {
696 return false;
697 }
698 let mut i = bytes.len() - 1;
699 if bytes[i] != 0 {
700 return false;
701 }
702 while i != 0 {
704 i -= 1;
705 if bytes[i] == 0 {
706 return false;
707 }
708 }
709 true
710 }
711 }
712
713 macro_rules! sys_type {
718 ({$(
719 $(#[$attr:meta])*
720 $vis:vis type $([$($windows_path:ident)::+])? $name:ident = $ty:ty;
721 )*}) => {
722 $(
723 $(#[$attr])*
724 $vis type $name = $ty;
725 )*
726 #[cfg(any(test, portable_atomic_test_no_std_static_assert_ffi))]
734 #[allow(
735 unused_imports,
736 clippy::cast_possible_wrap,
737 clippy::cast_sign_loss,
738 clippy::cast_possible_truncation
739 )]
740 const _: fn() = || {
741 #[cfg(not(any(target_os = "aix", windows)))]
742 use test_helper::sys;
743 #[cfg(target_os = "aix")]
744 use libc as sys;
745 $(
746 $(#[$attr])*
747 {
748 $(use windows_sys::$($windows_path)::+ as sys;)?
749 let _: $name = 0 as sys::$name;
750 }
751 )*
752 };
753 };
754 }
755 macro_rules! sys_struct {
760 ({$(
761 $(#[$attr:meta])*
762 $vis:vis struct $([$($windows_path:ident)::+])? $name:ident {$(
763 $(#[$field_attr:meta])*
764 $field_vis:vis $field_name:ident: $field_ty:ty,
765 )*}
766 )*}) => {
767 $(
768 $(#[$attr])*
769 #[derive(Clone, Copy)]
770 #[cfg_attr(
771 any(test, portable_atomic_test_no_std_static_assert_ffi),
772 derive(Debug, PartialEq)
773 )]
774 #[repr(C)]
775 $vis struct $name {$(
776 $(#[$field_attr])*
777 $field_vis $field_name: $field_ty,
778 )*}
779 )*
780 #[cfg(any(test, portable_atomic_test_no_std_static_assert_ffi))]
788 #[allow(unused_imports, clippy::undocumented_unsafe_blocks)]
789 const _: fn() = || {
790 #[cfg(not(any(target_os = "aix", windows)))]
791 use test_helper::sys;
792 #[cfg(target_os = "aix")]
793 use libc as sys;
794 $(
795 $(#[$attr])*
796 {
797 $(use windows_sys::$($windows_path)::+ as sys;)?
798 static_assert!(
799 core::mem::size_of::<$name>()
800 == core::mem::size_of::<sys::$name>()
801 );
802 let s: $name = unsafe { core::mem::zeroed() };
803 let _ = sys::$name {$(
805 $(#[$field_attr])*
806 $field_name: s.$field_name,
807 )*};
808 #[cfg(not(portable_atomic_no_offset_of))]
810 {$(
811 $(#[$field_attr])*
812 static_assert!(
813 core::mem::offset_of!($name, $field_name) ==
814 core::mem::offset_of!(sys::$name, $field_name),
815 );
816 )*}
817 }
818 )*
819 };
820 };
821 }
822 macro_rules! sys_const {
827 ({$(
828 $(#[$attr:meta])*
829 $vis:vis const $([$($windows_path:ident)::+])? $name:ident: $ty:ty = $val:expr;
830 )*}) => {
831 $(
832 $(#[$attr])*
833 $vis const $name: $ty = $val;
834 )*
835 #[cfg(any(test, portable_atomic_test_no_std_static_assert_ffi))]
843 #[allow(
844 unused_attributes, unused_imports,
846 clippy::cast_possible_wrap,
847 clippy::cast_sign_loss,
848 clippy::cast_possible_truncation,
849 )]
850 const _: fn() = || {
851 #[cfg(not(any(target_os = "aix", windows)))]
852 use test_helper::sys;
853 #[cfg(target_os = "aix")]
854 use libc as sys;
855 $(
856 $(#[$attr])*
857 {
858 $(use windows_sys::$($windows_path)::+ as sys;)?
859 sys_const_cmp!($name, $ty);
860 }
861 )*
862 };
863 };
864 }
865 #[cfg(any(test, portable_atomic_test_no_std_static_assert_ffi))]
866 macro_rules! sys_const_cmp {
867 (RTLD_DEFAULT, $ty:ty) => {
868 static_assert!(
871 unsafe {
874 core::mem::transmute::<$ty, usize>(RTLD_DEFAULT)
875 == core::mem::transmute::<$ty, usize>(sys::RTLD_DEFAULT)
876 }
877 );
878 };
879 ($name:ident, $ty:ty) => {
880 static_assert!($name == sys::$name as $ty);
881 };
882 }
883 macro_rules! sys_fn {
888 ({
889 $(#[$extern_attr:meta])*
890 extern $abi:literal {$(
891 $(#[$fn_attr:meta])*
892 $vis:vis fn $([$($windows_path:ident)::+])? $name:ident(
893 $($args:tt)*
894 ) $(-> $ret_ty:ty)?;
895 )*}
896 }) => {
897 $(#[$extern_attr])*
898 extern $abi {$(
899 $(#[$fn_attr])*
900 $vis fn $name($($args)*) $(-> $ret_ty)?;
901 )*}
902 #[cfg(any(test, portable_atomic_test_no_std_static_assert_ffi))]
910 #[allow(unused_imports)]
911 const _: fn() = || {
912 #[cfg(not(any(target_os = "aix", windows)))]
913 use test_helper::sys;
914 #[cfg(target_os = "aix")]
915 use libc as sys;
916 $(
917 $(#[$fn_attr])*
918 {
919 $(use windows_sys::$($windows_path)::+ as sys;)?
920 sys_fn_cmp!($abi fn $name($($args)*) $(-> $ret_ty)?);
921 }
922 )*
923 };
924 };
925 }
926 #[cfg(any(test, portable_atomic_test_no_std_static_assert_ffi))]
927 macro_rules! sys_fn_cmp {
928 (
929 $abi:literal fn $name:ident($($_arg_pat:ident: $arg_ty:ty),*, ...) $(-> $ret_ty:ty)?
930 ) => {
931 let mut _f: unsafe extern $abi fn($($arg_ty),*, ...) $(-> $ret_ty)? = $name;
932 _f = sys::$name;
933 };
934 (
935 $abi:literal fn $name:ident($($_arg_pat:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?
936 ) => {
937 let mut _f: unsafe extern $abi fn($($arg_ty),*) $(-> $ret_ty)? = $name;
938 _f = sys::$name;
939 };
940 }
941
942 #[allow(
943 clippy::alloc_instead_of_core,
944 clippy::std_instead_of_alloc,
945 clippy::std_instead_of_core,
946 clippy::undocumented_unsafe_blocks,
947 clippy::wildcard_imports
948 )]
949 #[cfg(test)]
950 mod tests {
951 #[test]
952 fn test_c_macro() {
953 #[track_caller]
954 fn t(s: &crate::utils::ffi::CStr, raw: &[u8]) {
955 assert_eq!(s.to_bytes_with_nul(), raw);
956 }
957 t(c!(""), b"\0");
958 t(c!("a"), b"a\0");
959 t(c!("abc"), b"abc\0");
960 t(c!(concat!("abc", "d")), b"abcd\0");
961 }
962
963 #[test]
964 fn test_is_c_str() {
965 #[track_caller]
966 fn t(bytes: &[u8]) {
967 assert_eq!(
968 super::_const_is_c_str(bytes),
969 std::ffi::CStr::from_bytes_with_nul(bytes).is_ok()
970 );
971 }
972 t(b"\0");
973 t(b"a\0");
974 t(b"abc\0");
975 t(b"");
976 t(b"a");
977 t(b"abc");
978 t(b"\0a");
979 t(b"\0a\0");
980 t(b"ab\0c\0");
981 t(b"\0\0");
982 }
983 }
984}