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}