• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 std::path::Path;
16 
17 use crate::quote_block;
18 
19 /// Generate the file preamble.
generate(path: &Path) -> String20 pub fn generate(path: &Path) -> String {
21     let mut code = String::new();
22     let filename = path.file_name().unwrap().to_str().expect("non UTF-8 filename");
23     // TODO(mgeisler): Make the  generated code free from warnings.
24     //
25     // The code either needs
26     //
27     // clippy_lints: "none",
28     // lints: "none",
29     //
30     // in the Android.bp file, or we need to add
31     //
32     // #![allow(warnings, missing_docs)]
33     //
34     // to the generated code. We cannot add the module-level attribute
35     // here because of how the generated code is used with include! in
36     // lmp/src/packets.rs.
37     code.push_str(&format!("// @generated rust packets from {filename}\n\n"));
38 
39     code.push_str(&quote_block! {
40         use bytes::{Buf, BufMut, Bytes, BytesMut};
41         use std::convert::{TryFrom, TryInto};
42         use std::cell::Cell;
43         use std::fmt;
44         use std::sync::Arc;
45         use thiserror::Error;
46     });
47 
48     code.push_str(&quote_block! {
49         type Result<T> = std::result::Result<T, Error>;
50     });
51 
52     code.push_str(&quote_block! {
53         /// Private prevents users from creating arbitrary scalar values
54         /// in situations where the value needs to be validated.
55         /// Users can freely deref the value, but only the backend
56         /// may create it.
57         #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
58         pub struct Private<T>(T);
59 
60         impl<T> std::ops::Deref for Private<T> {
61             type Target = T;
62             fn deref(&self) -> &Self::Target {
63                 &self.0
64             }
65         }
66     });
67 
68     code.push_str(&quote_block! {
69         #[derive(Debug, Error)]
70         pub enum Error {
71             #[error("Packet parsing failed")]
72             InvalidPacketError,
73             #[error("{field} was {value:x}, which is not known")]
74             ConstraintOutOfBounds { field: String, value: u64 },
75             #[error("Got {actual:x}, expected {expected:x}")]
76             InvalidFixedValue { expected: u64, actual: u64 },
77             #[error("when parsing {obj} needed length of {wanted} but got {got}")]
78             InvalidLengthError { obj: String, wanted: usize, got: usize },
79             #[error("array size ({array} bytes) is not a multiple of the element size ({element} bytes)")]
80             InvalidArraySize { array: usize, element: usize },
81             #[error("Due to size restrictions a struct could not be parsed.")]
82             ImpossibleStructError,
83             #[error("when parsing field {obj}.{field}, {value} is not a valid {type_} value")]
84             InvalidEnumValueError { obj: String, field: String, value: u64, type_: String },
85             #[error("expected child {expected}, got {actual}")]
86             InvalidChildError { expected: &'static str, actual: String },
87         }
88     });
89 
90     code.push_str(&quote_block! {
91         pub trait Packet {
92             fn to_bytes(self) -> Bytes;
93             fn to_vec(self) -> Vec<u8>;
94         }
95     });
96 
97     code
98 }
99 
100 #[cfg(test)]
101 mod tests {
102     use super::*;
103     use crate::test_utils::{assert_snapshot_eq, rustfmt};
104 
105     #[test]
test_generate_preamble()106     fn test_generate_preamble() {
107         let actual_code = generate(Path::new("some/path/foo.pdl"));
108         assert_snapshot_eq("tests/generated/preamble.rs", &rustfmt(&actual_code));
109     }
110 }
111