contrail_derive/
lib.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public License,
3 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4 * obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7//! Custom derive for `contrail::mem::Bytes`.
8//!
9//! This crate is internal to `contrail`; there's no reason to import it yourself.
10#![recursion_limit = "128"]
11
12extern crate proc_macro;
13extern crate proc_macro2;
14#[macro_use]
15extern crate quote;
16extern crate syn;
17
18#[proc_macro_derive(Bytes)]
19pub fn bytes_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
20    let input: proc_macro2::TokenStream = input.into();
21    let derive_input: syn::DeriveInput =
22        syn::parse2(input).expect("could not parse as syn::DeriveInput");
23    let name = &derive_input.ident;
24
25    if derive_input.generics.type_params().count() > 0
26        || derive_input.generics.lifetimes().count() > 0
27        || derive_input.generics.const_params().count() > 0
28    {
29        panic!("cannot derive Bytes for structs with generic parameters");
30    }
31
32    let impl_tokens: proc_macro2::TokenStream = quote! {
33        impl contrail::mem::Bytes for #name {
34            const LENGTH: usize = std::mem::size_of::<#name>();
35
36            #[inline(always)]
37            unsafe fn read_bytes(bytes: &[u8]) -> #name {
38                // safe assuming that the length of the byte slice is Self::LENGTH.
39                let byte_array = *(bytes.as_ptr() as *const [u8; std::mem::size_of::<#name>()]);
40                // safe assuming that the byte slice represents a valid value of type T.
41                std::mem::transmute::<[u8; std::mem::size_of::<#name>()], #name>(byte_array)
42            }
43
44            #[inline(always)]
45            unsafe fn write_bytes(self, bytes: &mut [u8]) {
46                // safe for Copy + 'static types
47                let byte_array = std::mem::transmute::<#name, [u8; std::mem::size_of::<#name>()]>(self);
48                // safe assuming that the length of the byte slice is Self::LENGTH.
49                bytes.copy_from_slice(&byte_array);
50            }
51        }
52    };
53
54    impl_tokens.into()
55}