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("e_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("e_block! {
49 type Result<T> = std::result::Result<T, Error>;
50 });
51
52 code.push_str("e_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("e_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("e_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