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
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#![no_std]
#![allow(warnings)]

//! Typic helps you transmute fearlessly. It worries about the subtleties of
//! ***[soundness]*** and ***[safety]*** so you don't have to!
//!
//! Just import it and replace your `#[repr(...)]` attributes with `#[typic::repr(...)]`:
//! ```
//! // Import it!
//! use typic::{self, transmute::StableTransmuteInto, stability::StableABI};
//!
//! // Update your attributes!
//! #[typic::repr(C)]
//! #[derive(StableABI)]
//! pub struct Foo(pub u8, pub u16);
//!
//! // Transmute fearlessly!
//! let _ : Foo = 64u32.transmute_into(); // Alchemy achieved!
//! ```
//! ```compile_fail
//! # use typic::{self, TransmuteInto};
//! # #[typic::repr(C)]
//! # #[derive(StableABI)]
//! # struct Foo(pub u8, pub u16);
//! let _ : u32 = Foo(16, 12).transmute_into(); // Compile Error!
//! ```
//!
//! [soundness]: crate::transmute::unsafe_transmutation#when-is-a-transmutation-sound
//! [safety]: crate::transmute::safe_transmutation

#[doc(hidden)]
pub mod docs {
    pub mod prelude {
        pub use crate::stability::StableABI;
        pub use crate::transmute::{unsafe_transmute, StableTransmuteInto};
        use crate::typic;
        pub use core::mem;
        pub use core::num::NonZeroU8;

        #[typic::repr(C)]
        #[derive(Default, StableABI)]
        pub struct Padded(pub u8, pub u16, pub u8);

        #[typic::repr(C)]
        #[derive(Default, StableABI)]
        pub struct Packed(pub u16, pub u16, pub u16);

        #[typic::repr(C)]
        #[derive(Default, StableABI)]
        pub struct Constrained {
            wizz: i8,
            bang: u8,
        }

        impl Constrained {
            /// the sum of `wizz` and `bang` must be greater than or equal to zero.
            pub fn new(wizz: i8, bang: u8) -> Self {
                assert!((wizz as i16) / (bang as i16) >= 0);
                Constrained { wizz, bang }
            }

            pub fn something_dangerous(&self) {
                unsafe {
                    // do something that's only safe if `wizz + bang >= 0`
                }
            }
        }

        #[typic::repr(C)]
        #[derive(Default, StableABI)]
        pub struct Unconstrained {
            pub wizz: u8,
            pub bang: i8,
        }
    }
}

#[doc(hidden)]
#[deprecated(note = "TODO")]
pub enum TODO {}

#[doc(hidden)]
pub mod private {
    pub mod bytelevel;
    pub mod highlevel;
    pub mod layout;
    pub mod num;
    pub mod stability;
    pub mod target;
    pub mod transmute;
}

#[doc(hidden)]
pub use private::highlevel as internal;

/// Use `#[typic::repr(...)]` instead of `#[repr(...)]` on your type definitions.
#[doc(inline)]
pub use typic_derive::repr;

#[doc(inline)]
pub use private::stability;

pub mod transmute;

mod typic {
    pub use super::*;
}

/// Details about the layout of types.
///
/// [`SizeOf`]: crate::layout::SizeOf
/// [`zerocopy`]: https://crates.io/crates/zerocopy
/// [`AsBytes`]: https://docs.rs/zerocopy/0.2.*/zerocopy/trait.AsBytes.html
/// [`FromBytes`]: https://docs.rs/zerocopy/0.2.*/zerocopy/trait.FromBytes.html
/// [`Unaligned`]: https://docs.rs/zerocopy/0.2.*/zerocopy/trait.Unaligned.html
///
/// Useful for building your own abstractions over Typic. For instance, we can
/// use [`SizeOf`] to implement [`zerocopy`]'s [`FromBytes`], [`AsBytes`] and
/// [`Unaligned`] marker traits:
///
/// ```
/// use typic::{layout::{Layout, SizeOf}, transmute::TransmuteInto, transmute::TransmuteFrom};
/// use generic_array::{ArrayLength as Length, GenericArray as Array};
/// use typenum::U1;
///
/// /// Indicates `Self` can be produced from an
/// /// appropriately-sized array of arbitrarily
/// /// initialized bytes.
/// pub trait FromBytes {}
///
/// impl<T> FromBytes for T
/// where
///     T: Layout,
///     SizeOf<T>: Length<u8>,
///     T: TransmuteFrom<Array<u8, SizeOf<T>>>
/// {}
///
/// /// Indicates `Self` can be converted into an
/// /// appropriately-sized array of arbitrarily
/// /// initialized bytes.
/// pub trait AsBytes {}
///
/// impl<T> AsBytes for T
/// where
///     T: Layout,
///     SizeOf<T>: Length<u8>,
///     T: TransmuteInto<Array<u8, SizeOf<T>>>
/// {}
///
/// /// Indicates `Self` has no alignment requirement.
/// pub trait Unaligned {}
///
/// impl<T> Unaligned for T
/// where
///     T: Layout<Align=U1>,
/// {}
/// ```
pub mod layout {
    use crate::internal::{Private, Public};
    use crate::private::{layout, num};
    use generic_array::ArrayLength;

    /// Type-level information about type representation.
    pub trait Layout: layout::Layout<Public> {
        /// The size of `Self`.
        ///
        /// ```
        /// use typenum::*;
        /// use static_assertions::*;
        /// use typic::layout::Layout;
        ///
        /// assert_type_eq_all!(U4, <[u16; 2] as Layout>::Size);
        /// ```
        type Size: num::Unsigned + ArrayLength<u8>;

        /// The minimum alignment of `Self`.
        ///
        /// ```
        /// use typenum::*;
        /// use static_assertions::*;
        /// use typic::layout::Layout;
        ///
        /// assert_type_eq_all!(U2, <[u16; 2] as Layout>::Align);
        /// ```
        type Align: num::Unsigned;
    }

    impl<T> Layout for T
    where
        T: layout::Layout<Public>,
    {
        type Size = <T as layout::Layout<Public>>::Size;
        type Align = <T as layout::Layout<Public>>::Align;
    }

    /// Get the size of `T` (if `T: Layout`).
    ///
    /// ```
    /// use typenum::*;
    /// use static_assertions::*;
    /// use typic::layout::SizeOf;
    ///
    /// assert_type_eq_all!(U4, SizeOf<[u16; 2]>);
    /// ```
    pub type SizeOf<T> = <T as Layout>::Size;

    /// Get the minimum alignment of `T` (if `T: Layout`).
    ///
    /// ```
    /// use typenum::*;
    /// use static_assertions::*;
    /// use typic::layout::AlignOf;
    ///
    /// assert_type_eq_all!(U2, AlignOf<[u16; 2]>);
    /// ```
    pub type AlignOf<T> = <T as Layout>::Align;
}

/// Examples demonstrating typic's ability to express common abstractions.
pub mod extras {

    /// [Zerocopy](https://docs.rs/zerocopy)-style marker traits.
    pub mod zerocopy {
        use crate::layout::*;
        use crate::transmute::*;
        use typenum::U1;
        use generic_array::{ArrayLength as Length, GenericArray as Array};

        /// Indicates `Self` can be produced from an
        /// appropriately-sized array of arbitrarily
        /// initialized bytes.
        pub unsafe trait FromBytes<O: TransmuteOptions = ()>
        {}

        unsafe impl<T, O: TransmuteOptions> FromBytes<O> for T
        where
            T: Layout + TransmuteFrom<Array<u8, SizeOf<T>>, O>
        {}


        /// Indicates `Self` can be converted into an
        /// appropriately-sized array of arbitrarily
        /// initialized bytes.
        pub unsafe trait AsBytes<O: TransmuteOptions = ()> {}

        unsafe impl<T, O: TransmuteOptions> AsBytes<O> for T
        where
            T: Layout + TransmuteInto<Array<u8, SizeOf<T>>, O>
        {}


        /// Indicates `Self` has no alignment requirement.
        pub trait Unaligned {}

        impl<T> Unaligned for T
        where
            T: Layout<Align=U1>,
        {}
    }

    /// [Bytemuck](https://docs.rs/bytemuck)-style casting functions.
    pub mod bytemuck {
        use crate::transmute::*;
        use core::mem::{align_of, size_of, size_of_val};

        /// Try to convert a `&T` into `&U`.
        ///
        /// This produces `None` if the referent isn't appropriately
        /// aligned, as required by the destination type.
        ///
        /// Like [`bytemuck::try_cast_ref`], except that invariant
        /// that `T` and `U` have the same size is statically enforced.
        ///
        /// [`bytemuck::try_cast_ref`]: https://docs.rs/bytemuck/1.2.0/bytemuck/fn.try_cast_ref.html
        pub fn try_cast_ref<'t, 'u, T, U>(src: &'t T) -> Option<&'u U>
        where
            &'t T: UnsafeTransmuteInto<&'u U, neglect::Alignment>,
        {
            if align_of::<U>() > align_of::<T>() && (src as *const T as usize) % align_of::<U>() != 0 {
                None
            } else {
                // Sound, because we dynamically enforce the alignment
                // requirement, whose static check we chose to neglect.
                Some(unsafe { src.unsafe_transmute_into() })
            }
        }

        use core::slice;
        use generic_array::{ArrayLength as Length, GenericArray as Array};
        use crate::layout::*;

        /// Try to convert a `&T` into `&U`.
        ///
        /// This produces `None` if the referent isn't appropriately
        /// aligned, as required by the destination type.
        ///
        /// Like [`bytemuck::try_cast_slice`], except that invariant
        /// that `T` and `U` have the same size is statically enforced.
        ///
        /// If const generics were stable, the trait bound would
        /// be instead written as just:
        /// ```ignore
        /// &'t [T; size_of::<U>()]:
        ///     TransmuteInto<&'u [U; size_of::<T>()]>
        /// ```
        ///
        /// [`bytemuck::try_cast_slice`]: https://docs.rs/bytemuck/1.2.0/bytemuck/fn.try_cast_slice.html
        pub fn try_cast_slice<'t, 'u, T, U>(src: &'t [T]) -> Option<&'u [U]>
        where
            &'t Array<T, SizeOf<U>>: TransmuteInto<&'u Array<U, SizeOf<T>>>,

            T: Layout,
            U: Layout,
            SizeOf<T>: 'u + Length<U>,
            SizeOf<U>: 't + Length<T>,
        {
            if align_of::<U>() > align_of::<T>() && (src.as_ptr() as usize) % align_of::<U>() != 0 {
                None
            } else {
                let len = size_of_val(src).checked_div(size_of::<U>()).unwrap_or(0);
                Some(unsafe {
                  slice::from_raw_parts(src.as_ptr() as *const U, len)
                })
            }
        }
    }
}