1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! Traits to represent `repr`s
//!
//! If it is important for a generic parameter to have a particular `repr`, you can use
//! the traits in this crate to ensure that it has the needed `repr`.
//!
//! For example, if you have an `unsafe` function that requires a specific `repr`,
//! you can use these traits to create a safe wrapper around it.
//!
//! ```rust
//! use repr_trait::Packed;
//!
//! // Safety: Only safe to call when T has #[repr(packed)]
//! unsafe fn safe_when_packed<T>(_param: T) {
//!     unimplemented!()
//! }
//!
//! fn safe_wrapper<T: Packed>(param: T) {
//!     // Safety: Safe because T is guaranteed to be #[repr(packed)]
//!     unsafe {
//!         safe_when_packed(param)
//!     }
//! }
//! ```
//!
//! Implementing the traits from this crate is easy using derive macros. There is a derive
//! macro for each included trait.
//!
//! ```rust
//! # use repr_trait::Packed;
//! # fn safe_wrapper<T: Packed>(param: T) { param; }
//! #[derive(Packed, Default)]
//! #[repr(packed)]
//! struct PackedData(u32, u8);
//!
//! safe_wrapper(PackedData(123, 45));
//! ```
//!
//! If the appropriate `repr` is not specified, the derive macro will refuse to compile.
//!
//! ```rust,compile_fail
//! #[derive(Packed)]
//! struct NotPacked(u32, u8);
//! ```

macro_rules! trait_and_docs {
    ($tr:ident as $repr:expr) => {
        trait_and_docs!(@
            $tr
            trait_doc concat!("Trait for types declared with `#[repr(", $repr, ")]`."),
            derive_doc concat!("Derive macro for [`", stringify!($tr), "`](trait@", stringify!($tr), ")")
        );
    };
    (@ $tr:ident trait_doc $trait_doc:expr, derive_doc $derive_doc:expr) => {
        #[doc = $trait_doc]
        ///
        /// # Safety
        ///
        /// This trait should only be implemented for types with the correct `repr`. Because `repr`s
        /// cannot be checked by the compiler, this trait is `unsafe`.
        ///
        /// Use the corresponding derive macro to safely derive this on any type with the correct
        /// `repr`.
        pub unsafe trait $tr {}

        #[doc = $derive_doc]
        ///
        /// Can be added to any type with the correct
        pub use repr_trait_derive::$tr;
    }

}

trait_and_docs!(C as "C");
trait_and_docs!(Packed as "packed");
trait_and_docs!(Transparent as "transparent");

//pub use repr_trait_derive::Transparent;
//pub use repr_trait_derive::C;

#[cfg(test)]
mod test {
    // Due to https://github.com/dtolnay/trybuild/issues/58, all trybuild tests must
    // run in the same test case.
    #[test]
    fn test_compilation() {
        let t = trybuild::TestCases::new();
        t.compile_fail("test/packed_fail.rs");
        t.pass("test/packed_pass.rs");

        t.compile_fail("test/transparent_fail.rs");
        t.pass("test/transparent_pass.rs");

        t.compile_fail("test/c_fail.rs");
        t.pass("test/c_pass.rs");
    }
}