• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, The Android Open Source Project
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 //     http://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 //! This module implement size spec parsing for mmd.
16 
17 /// Error from [parse_size_spec].
18 #[derive(Debug, thiserror::Error)]
19 pub enum ParsingError {
20     /// Size spec was not specified
21     #[error("Size spec is empty")]
22     EmptySpec,
23     /// Specified percentage is out of range
24     #[error("Percentage out of range: {0} (expected to be less than {1})")]
25     PercentageOutOfRange(u64, u64),
26     /// Parsing int error
27     #[error("Size spec is not a valid integer: {0}")]
28     ParsingInt(#[from] std::num::ParseIntError),
29 }
30 
31 /// Parse zram size that can be specified by a percentage or an absolute value.
parse_size_spec( spec: &str, block_size: u64, block_count: u64, max_percentage_allowed: u64, ) -> Result<u64, ParsingError>32 pub fn parse_size_spec(
33     spec: &str,
34     block_size: u64,
35     block_count: u64,
36     max_percentage_allowed: u64,
37 ) -> Result<u64, ParsingError> {
38     if spec.is_empty() {
39         return Err(ParsingError::EmptySpec);
40     }
41 
42     if let Some(percentage_str) = spec.strip_suffix('%') {
43         let percentage = percentage_str.parse::<u64>()?;
44 
45         if percentage > max_percentage_allowed {
46             return Err(ParsingError::PercentageOutOfRange(percentage, max_percentage_allowed));
47         }
48         return Ok(block_count * percentage / 100 * block_size);
49     }
50 
51     let size = spec.parse::<u64>()?;
52     Ok(size)
53 }
54 
55 #[cfg(test)]
56 mod tests {
57     use super::*;
58     const DEFAULT_BLOCK_SIZE: u64 = 4096;
59     const DEFAULT_BLOCK_COUNT: u64 = 998875;
60     const MAX_PERCENTAGE_ALLOWED: u64 = 500;
61 
62     #[test]
parse_size_spec_invalid()63     fn parse_size_spec_invalid() {
64         assert!(parse_size_spec(
65             "",
66             DEFAULT_BLOCK_SIZE,
67             DEFAULT_BLOCK_COUNT,
68             MAX_PERCENTAGE_ALLOWED
69         )
70         .is_err());
71         assert!(parse_size_spec(
72             "not_int%",
73             DEFAULT_BLOCK_SIZE,
74             DEFAULT_BLOCK_COUNT,
75             MAX_PERCENTAGE_ALLOWED
76         )
77         .is_err());
78         assert!(parse_size_spec(
79             "not_int",
80             DEFAULT_BLOCK_SIZE,
81             DEFAULT_BLOCK_COUNT,
82             MAX_PERCENTAGE_ALLOWED
83         )
84         .is_err());
85     }
86 
87     #[test]
parse_size_spec_percentage_out_of_range()88     fn parse_size_spec_percentage_out_of_range() {
89         assert!(parse_size_spec("201%", DEFAULT_BLOCK_SIZE, DEFAULT_BLOCK_COUNT, 200).is_err());
90     }
91 
92     #[test]
parse_size_spec_percentage()93     fn parse_size_spec_percentage() {
94         assert_eq!(parse_size_spec("0%", 4096, 5, MAX_PERCENTAGE_ALLOWED).unwrap(), 0);
95         assert_eq!(parse_size_spec("33%", 4096, 5, MAX_PERCENTAGE_ALLOWED).unwrap(), 4096);
96         assert_eq!(parse_size_spec("50%", 4096, 5, MAX_PERCENTAGE_ALLOWED).unwrap(), 8192);
97         assert_eq!(parse_size_spec("90%", 4096, 5, MAX_PERCENTAGE_ALLOWED).unwrap(), 16384);
98         assert_eq!(parse_size_spec("100%", 4096, 5, MAX_PERCENTAGE_ALLOWED).unwrap(), 20480);
99         assert_eq!(parse_size_spec("200%", 4096, 5, MAX_PERCENTAGE_ALLOWED).unwrap(), 40960);
100         assert_eq!(
101             parse_size_spec("100%", 4096, 3995500, MAX_PERCENTAGE_ALLOWED).unwrap(),
102             16365568000
103         );
104     }
105 
106     #[test]
parse_size_spec_bytes()107     fn parse_size_spec_bytes() {
108         assert_eq!(
109             parse_size_spec(
110                 "1234567",
111                 DEFAULT_BLOCK_SIZE,
112                 DEFAULT_BLOCK_COUNT,
113                 MAX_PERCENTAGE_ALLOWED
114             )
115             .unwrap(),
116             1234567
117         );
118     }
119 }
120