1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use quote::quote;
16 use std::path::Path;
17 
18 /// Generate the file preamble.
generate(path: &Path) -> proc_macro2::TokenStream19 pub fn generate(path: &Path) -> proc_macro2::TokenStream {
20     // TODO(mgeisler): Make the  generated code free from warnings.
21     //
22     // The code either needs
23     //
24     // clippy_lints: "none",
25     // lints: "none",
26     //
27     // in the Android.bp file, or we need to add
28     //
29     // #![allow(warnings, missing_docs)]
30     //
31     // to the generated code. We cannot add the module-level attribute
32     // here because of how the generated code is used with include! in
33     // lmp/src/packets.rs.
34     let filename = path.file_name().unwrap().to_str().expect("non UTF-8 filename");
35     let module_doc_string = format!(" @generated rust packets from {filename}.");
36     // TODO(mgeisler): the doc comment below should be an outer
37     // comment (#![doc = ...]). However, people include the generated
38     // code in the middle of another module via include_str!:
39     //
40     // fn before() {}
41     // include_str!("generated.rs")
42     // fn after() {}
43     //
44     // It is illegal to have a //! comment in the middle of a file. We
45     // should refactor such usages to instead look like this:
46     //
47     // fn before() {}
48     // mod foo { include_str!("generated.rs") }
49     // use foo::*;
50     // fn after() {}
51     quote! {
52         #[doc = #module_doc_string]
53 
54         use bytes::{Buf, BufMut, Bytes, BytesMut};
55         use std::convert::{TryFrom, TryInto};
56         use std::cell::Cell;
57         use std::fmt;
58         use std::result::Result;
59         use pdl_runtime::{DecodeError, EncodeError, Packet};
60 
61         /// Private prevents users from creating arbitrary scalar values
62         /// in situations where the value needs to be validated.
63         /// Users can freely deref the value, but only the backend
64         /// may create it.
65         #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
66         pub struct Private<T>(T);
67 
68         impl<T> std::ops::Deref for Private<T> {
69             type Target = T;
70             fn deref(&self) -> &Self::Target {
71                 &self.0
72             }
73         }
74 
75         impl<T: std::fmt::Debug> std::fmt::Debug for Private<T> {
76             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77                 T::fmt(&self.0, f)
78             }
79         }
80     }
81 }
82 
83 #[cfg(test)]
84 mod tests {
85     use super::*;
86     use crate::test_utils::{assert_snapshot_eq, format_rust};
87 
88     #[test]
test_generate_preamble()89     fn test_generate_preamble() {
90         let actual_code = generate(Path::new("some/path/foo.pdl")).to_string();
91         assert_snapshot_eq("tests/generated/preamble.rs", &format_rust(&actual_code));
92     }
93 }
94