fluence_sdk_wit/token_stream_generator/
record_generator.rs

1/*
2 * Copyright 2020 Fluence Labs Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17mod record_serializer;
18mod record_deserializer;
19mod field_values_builder;
20
21use field_values_builder::*;
22use record_deserializer::*;
23use record_serializer::*;
24
25use crate::new_ident;
26use crate::ast_types::AstRecord;
27use crate::ast_types::AstRecordFields;
28
29impl quote::ToTokens for AstRecord {
30    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
31        let original = &self.original;
32        crate::prepare_global_data!(
33            Record,
34            self,
35            self.name,
36            data,
37            data_size,
38            global_static_name,
39            section_name
40        );
41        let record_name = new_ident!(self.name);
42
43        let serializer_fn = generate_serializer_fn(self);
44        let deserializer_fn = generate_deserializer_fn(self);
45
46        let glue_code = quote::quote! {
47            #original
48
49            // used_id_fce is a special feature that indicates that this struct will be used inside
50            // FCE for some internal needs
51            #[cfg(target_arch = "wasm32")]
52            #[doc(hidden)]
53            #[allow(clippy::all)]
54            impl #record_name {
55                #serializer_fn
56
57                #deserializer_fn
58            }
59
60            #[cfg(target_arch = "wasm32")]
61            #[doc(hidden)]
62            #[allow(clippy::all)]
63            #[link_section = #section_name]
64            pub static #global_static_name: [u8; #data_size] = { *#data };
65        };
66
67        tokens.extend(glue_code);
68    }
69}
70
71fn generate_serializer_fn(record: &AstRecord) -> proc_macro2::TokenStream {
72    let serializer = record.generate_serializer();
73    let fields_count = match &record.fields {
74        AstRecordFields::Named(fields) => fields.len(),
75        AstRecordFields::Unnamed(fields) => fields.len(),
76        AstRecordFields::Unit => return proc_macro2::TokenStream::new(),
77    };
78
79    quote::quote! {
80        pub fn __fce_generated_serialize(&self) -> *const u8 {
81            // 4 is an average size of a possible record field
82            let mut raw_record: Vec<u8> = Vec::with_capacity(4 * #fields_count);
83
84            #serializer
85
86            let raw_record_ptr = raw_record.as_ptr();
87            fluence::internal::add_object_to_release(Box::new(raw_record));
88
89            raw_record_ptr as _
90        }
91    }
92}
93
94fn generate_deserializer_fn(record: &AstRecord) -> proc_macro2::TokenStream {
95    let RecordDerDescriptor {
96        fields_der,
97        record_ctor,
98    } = record.generate_der();
99
100    let fields = match &record.fields {
101        AstRecordFields::Named(fields) => fields,
102        AstRecordFields::Unnamed(fields) => fields,
103        AstRecordFields::Unit => return proc_macro2::TokenStream::new(),
104    };
105
106    let record_size = crate::utils::get_record_size(fields.iter().map(|ast_field| &ast_field.ty));
107
108    quote::quote! {
109        pub unsafe fn __fce_generated_deserialize(record_ptr: *const u8) -> Self {
110            let raw_record: Vec<u8> = Vec::from_raw_parts(record_ptr as _, #record_size, #record_size);
111
112            #fields_der
113
114            #record_ctor
115        }
116    }
117}