repr_trait/
lib.rs

1//! Traits to represent `repr`s
2//!
3//! If it is important for a generic parameter to have a particular `repr`, you can use
4//! the traits in this crate to ensure that it has the needed `repr`.
5//!
6//! For example, if you have an `unsafe` function that requires a specific `repr`,
7//! you can use these traits to create a safe wrapper around it.
8//!
9//! ```rust
10//! use repr_trait::Packed;
11//!
12//! // Safety: Only safe to call when T has #[repr(packed)]
13//! unsafe fn safe_when_packed<T>(_param: T) {
14//!     unimplemented!()
15//! }
16//!
17//! fn safe_wrapper<T: Packed>(param: T) {
18//!     // Safety: Safe because T is guaranteed to be #[repr(packed)]
19//!     unsafe {
20//!         safe_when_packed(param)
21//!     }
22//! }
23//! ```
24//!
25//! Implementing the traits from this crate is easy using derive macros. There is a derive
26//! macro for each included trait.
27//!
28//! ```rust
29//! # use repr_trait::Packed;
30//! # fn safe_wrapper<T: Packed>(param: T) { param; }
31//! #[derive(Packed, Default)]
32//! #[repr(packed)]
33//! struct PackedData(u32, u8);
34//!
35//! safe_wrapper(PackedData(123, 45));
36//! ```
37//!
38//! If the appropriate `repr` is not specified, the derive macro will refuse to compile.
39//!
40//! ```rust,compile_fail
41//! #[derive(Packed)]
42//! struct NotPacked(u32, u8);
43//! ```
44
45macro_rules! trait_and_docs {
46    ($tr:ident as $repr:expr) => {
47        trait_and_docs!(@
48            $tr
49            trait_doc concat!("Trait for types declared with `#[repr(", $repr, ")]`."),
50            derive_doc concat!("Derive macro for [`", stringify!($tr), "`](trait@", stringify!($tr), ")")
51        );
52    };
53    (@ $tr:ident trait_doc $trait_doc:expr, derive_doc $derive_doc:expr) => {
54        #[doc = $trait_doc]
55        ///
56        /// # Safety
57        ///
58        /// This trait should only be implemented for types with the correct `repr`. Because `repr`s
59        /// cannot be checked by the compiler, this trait is `unsafe`.
60        ///
61        /// Use the corresponding derive macro to safely derive this on any type with the correct
62        /// `repr`.
63        pub unsafe trait $tr {}
64
65        #[doc = $derive_doc]
66        ///
67        /// Can be added to any type with the correct
68        pub use repr_trait_derive::$tr;
69    }
70
71}
72
73trait_and_docs!(C as "C");
74trait_and_docs!(Packed as "packed");
75trait_and_docs!(Transparent as "transparent");
76
77//pub use repr_trait_derive::Transparent;
78//pub use repr_trait_derive::C;
79
80#[cfg(test)]
81mod test {
82    // Due to https://github.com/dtolnay/trybuild/issues/58, all trybuild tests must
83    // run in the same test case.
84    #[test]
85    fn test_compilation() {
86        let t = trybuild::TestCases::new();
87        t.compile_fail("test/packed_fail.rs");
88        t.pass("test/packed_pass.rs");
89
90        t.compile_fail("test/transparent_fail.rs");
91        t.pass("test/transparent_pass.rs");
92
93        t.compile_fail("test/c_fail.rs");
94        t.pass("test/c_pass.rs");
95    }
96}