xref: /aosp_15_r20/build/make/tools/aconfig/aconfig_storage_file/src/flag_value.rs (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
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 
17 //! flag value module defines the flag value file format and methods for serialization
18 //! and deserialization
19 
20 use crate::{read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
21 use crate::{AconfigStorageError, StorageFileType};
22 use anyhow::anyhow;
23 use serde::{Deserialize, Serialize};
24 use std::fmt;
25 
26 /// Flag value header struct
27 #[derive(PartialEq, Serialize, Deserialize)]
28 pub struct FlagValueHeader {
29     pub version: u32,
30     pub container: String,
31     pub file_type: u8,
32     pub file_size: u32,
33     pub num_flags: u32,
34     pub boolean_value_offset: u32,
35 }
36 
37 /// Implement debug print trait for header
38 impl fmt::Debug for FlagValueHeader {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result39     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40         writeln!(
41             f,
42             "Version: {}, Container: {}, File Type: {:?}, File Size: {}",
43             self.version,
44             self.container,
45             StorageFileType::try_from(self.file_type),
46             self.file_size
47         )?;
48         writeln!(
49             f,
50             "Num of Flags: {}, Value Offset:{}",
51             self.num_flags, self.boolean_value_offset
52         )?;
53         Ok(())
54     }
55 }
56 
57 impl FlagValueHeader {
58     /// Serialize to bytes
into_bytes(&self) -> Vec<u8>59     pub fn into_bytes(&self) -> Vec<u8> {
60         let mut result = Vec::new();
61         result.extend_from_slice(&self.version.to_le_bytes());
62         let container_bytes = self.container.as_bytes();
63         result.extend_from_slice(&(container_bytes.len() as u32).to_le_bytes());
64         result.extend_from_slice(container_bytes);
65         result.extend_from_slice(&self.file_type.to_le_bytes());
66         result.extend_from_slice(&self.file_size.to_le_bytes());
67         result.extend_from_slice(&self.num_flags.to_le_bytes());
68         result.extend_from_slice(&self.boolean_value_offset.to_le_bytes());
69         result
70     }
71 
72     /// Deserialize from bytes
from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>73     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
74         let mut head = 0;
75         let list = Self {
76             version: read_u32_from_bytes(bytes, &mut head)?,
77             container: read_str_from_bytes(bytes, &mut head)?,
78             file_type: read_u8_from_bytes(bytes, &mut head)?,
79             file_size: read_u32_from_bytes(bytes, &mut head)?,
80             num_flags: read_u32_from_bytes(bytes, &mut head)?,
81             boolean_value_offset: read_u32_from_bytes(bytes, &mut head)?,
82         };
83         if list.file_type != StorageFileType::FlagVal as u8 {
84             return Err(AconfigStorageError::BytesParseFail(anyhow!(
85                 "binary file is not a flag value file"
86             )));
87         }
88         Ok(list)
89     }
90 }
91 
92 /// Flag value list struct
93 #[derive(PartialEq, Serialize, Deserialize)]
94 pub struct FlagValueList {
95     pub header: FlagValueHeader,
96     pub booleans: Vec<bool>,
97 }
98 
99 /// Implement debug print trait for flag value
100 impl fmt::Debug for FlagValueList {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result101     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102         writeln!(f, "Header:")?;
103         write!(f, "{:?}", self.header)?;
104         writeln!(f, "Values:")?;
105         writeln!(f, "{:?}", self.booleans)?;
106         Ok(())
107     }
108 }
109 
110 impl FlagValueList {
111     /// Serialize to bytes
into_bytes(&self) -> Vec<u8>112     pub fn into_bytes(&self) -> Vec<u8> {
113         [
114             self.header.into_bytes(),
115             self.booleans.iter().map(|&v| u8::from(v).to_le_bytes()).collect::<Vec<_>>().concat(),
116         ]
117         .concat()
118     }
119 
120     /// Deserialize from bytes
from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>121     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
122         let header = FlagValueHeader::from_bytes(bytes)?;
123         let num_flags = header.num_flags;
124         let mut head = header.into_bytes().len();
125         let booleans =
126             (0..num_flags).map(|_| read_u8_from_bytes(bytes, &mut head).unwrap() == 1).collect();
127         let list = Self { header, booleans };
128         Ok(list)
129     }
130 }
131 
132 #[cfg(test)]
133 mod tests {
134     use super::*;
135     use crate::{
136         test_utils::create_test_flag_value_list, DEFAULT_FILE_VERSION, MAX_SUPPORTED_FILE_VERSION,
137     };
138 
139     #[test]
140     // this test point locks down the value list serialization
141     // TODO: b/376108268 - Use parameterized tests.
test_serialization_default()142     fn test_serialization_default() {
143         let flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
144 
145         let header: &FlagValueHeader = &flag_value_list.header;
146         let reinterpreted_header = FlagValueHeader::from_bytes(&header.into_bytes());
147         assert!(reinterpreted_header.is_ok());
148         assert_eq!(header, &reinterpreted_header.unwrap());
149 
150         let flag_value_bytes = flag_value_list.into_bytes();
151         let reinterpreted_value_list = FlagValueList::from_bytes(&flag_value_bytes);
152         assert!(reinterpreted_value_list.is_ok());
153         assert_eq!(&flag_value_list, &reinterpreted_value_list.unwrap());
154         assert_eq!(flag_value_bytes.len() as u32, header.file_size);
155     }
156 
157     #[test]
158     // this test point locks down the value list serialization
test_serialization_max()159     fn test_serialization_max() {
160         let flag_value_list = create_test_flag_value_list(MAX_SUPPORTED_FILE_VERSION);
161 
162         let header: &FlagValueHeader = &flag_value_list.header;
163         let reinterpreted_header = FlagValueHeader::from_bytes(&header.into_bytes());
164         assert!(reinterpreted_header.is_ok());
165         assert_eq!(header, &reinterpreted_header.unwrap());
166 
167         let flag_value_bytes = flag_value_list.into_bytes();
168         let reinterpreted_value_list = FlagValueList::from_bytes(&flag_value_bytes);
169         assert!(reinterpreted_value_list.is_ok());
170         assert_eq!(&flag_value_list, &reinterpreted_value_list.unwrap());
171         assert_eq!(flag_value_bytes.len() as u32, header.file_size);
172     }
173 
174     #[test]
175     // this test point locks down that version number should be at the top of serialized
176     // bytes
test_version_number()177     fn test_version_number() {
178         let flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
179         let bytes = &flag_value_list.into_bytes();
180         let mut head = 0;
181         let version_from_file = read_u32_from_bytes(bytes, &mut head).unwrap();
182         assert_eq!(version_from_file, DEFAULT_FILE_VERSION);
183     }
184 
185     #[test]
186     // this test point locks down file type check
test_file_type_check()187     fn test_file_type_check() {
188         let mut flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
189         flag_value_list.header.file_type = 123u8;
190         let error = FlagValueList::from_bytes(&flag_value_list.into_bytes()).unwrap_err();
191         assert_eq!(
192             format!("{:?}", error),
193             format!("BytesParseFail(binary file is not a flag value file)")
194         );
195     }
196 }
197