to_shmem.rs (2672B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 use crate::util::{add_predicate, fmap2_match, parse_field_attrs, parse_input_attrs}; 6 use darling::{FromDeriveInput, FromField}; 7 use proc_macro2::TokenStream; 8 use quote::quote; 9 use syn::{self, parse_quote}; 10 use synstructure::{BindStyle, Structure}; 11 12 pub fn derive(mut input: syn::DeriveInput) -> TokenStream { 13 let mut where_clause = input.generics.where_clause.take(); 14 let attrs = parse_input_attrs::<ShmemInputAttrs>(&input); 15 if !attrs.no_bounds { 16 for param in input.generics.type_params() { 17 add_predicate(&mut where_clause, parse_quote!(#param: ::to_shmem::ToShmem)); 18 } 19 } 20 for variant in Structure::new(&input).variants() { 21 for binding in variant.bindings() { 22 let attrs = parse_field_attrs::<ShmemFieldAttrs>(&binding.ast()); 23 if attrs.field_bound { 24 let ty = &binding.ast().ty; 25 add_predicate(&mut where_clause, parse_quote!(#ty: ::to_shmem::ToShmem)) 26 } 27 } 28 } 29 30 input.generics.where_clause = where_clause; 31 32 // Do all of the `to_shmem()?` calls before the `ManuallyDrop::into_inner()` 33 // calls, so that we don't drop a value in the shared memory buffer if one 34 // of the `to_shmem`s fails. 35 let match_body = fmap2_match( 36 &input, 37 BindStyle::Ref, 38 |binding| { 39 quote! { 40 ::to_shmem::ToShmem::to_shmem(#binding, builder)? 41 } 42 }, 43 |binding| { 44 Some(quote! { 45 ::std::mem::ManuallyDrop::into_inner(#binding) 46 }) 47 }, 48 ); 49 50 let name = &input.ident; 51 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); 52 53 quote! { 54 impl #impl_generics ::to_shmem::ToShmem for #name #ty_generics #where_clause { 55 #[allow(unused_variables, unreachable_code)] 56 fn to_shmem( 57 &self, 58 builder: &mut ::to_shmem::SharedMemoryBuilder, 59 ) -> ::to_shmem::Result<Self> { 60 Ok(::std::mem::ManuallyDrop::new( 61 match *self { 62 #match_body 63 } 64 )) 65 } 66 } 67 } 68 } 69 70 #[derive(Default, FromDeriveInput)] 71 #[darling(attributes(shmem), default)] 72 pub struct ShmemInputAttrs { 73 pub no_bounds: bool, 74 } 75 76 #[derive(Default, FromField)] 77 #[darling(attributes(shmem), default)] 78 pub struct ShmemFieldAttrs { 79 pub field_bound: bool, 80 }