1pub mod codec;
2pub mod traits;
3pub mod types;
4mod utils;
5
6pub use utils::*;
7
8use crate::types::errors::Result;
9
10#[derive(Debug, Clone, Default, PartialEq)]
11pub struct Configurable {
12 pub offset: u64,
14 pub data: Vec<u8>,
16}
17
18#[derive(Debug, Clone, Default, PartialEq)]
19pub struct Configurables {
20 pub offsets_with_data: Vec<Configurable>,
21}
22
23impl Configurables {
24 pub fn new(offsets_with_data: Vec<Configurable>) -> Self {
25 Self { offsets_with_data }
26 }
27
28 pub fn with_shifted_offsets(self, shift: i64) -> Result<Self> {
29 let new_offsets_with_data = self
30 .offsets_with_data
31 .into_iter()
32 .map(|c| {
33 let new_offset = if shift.is_negative() {
34 c.offset.checked_sub(shift.unsigned_abs())
35 } else {
36 c.offset.checked_add(shift.unsigned_abs())
37 };
38
39 let new_offset = new_offset.ok_or_else(|| {
40 crate::error!(
41 Other,
42 "Overflow occurred while shifting offset: {} + {shift}",
43 c.offset
44 )
45 })?;
46
47 Ok(Configurable {
48 offset: new_offset,
49 data: c.data,
50 })
51 })
52 .collect::<Result<Vec<_>>>()?;
53
54 Ok(Self {
55 offsets_with_data: new_offsets_with_data,
56 })
57 }
58
59 pub fn update_constants_in(&self, binary: &mut [u8]) {
60 for c in &self.offsets_with_data {
61 let offset = c.offset as usize;
62 binary[offset..offset + c.data.len()].copy_from_slice(&c.data)
63 }
64 }
65}
66
67impl From<Configurables> for Vec<Configurable> {
68 fn from(config: Configurables) -> Vec<Configurable> {
69 config.offsets_with_data.clone()
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_with_shifted_offsets_positive_shift() {
79 let offsets_with_data = vec![Configurable {
80 offset: 10u64,
81 data: vec![1, 2, 3],
82 }];
83 let configurables = Configurables::new(offsets_with_data.clone());
84 let shifted_configurables = configurables.with_shifted_offsets(5).unwrap();
85 let expected_offsets_with_data = vec![Configurable {
86 offset: 15u64,
87 data: vec![1, 2, 3],
88 }];
89 assert_eq!(
90 shifted_configurables.offsets_with_data,
91 expected_offsets_with_data
92 );
93 }
94
95 #[test]
96 fn test_with_shifted_offsets_negative_shift() {
97 let offsets_with_data = vec![Configurable {
98 offset: 10u64,
99 data: vec![4, 5, 6],
100 }];
101 let configurables = Configurables::new(offsets_with_data.clone());
102 let shifted_configurables = configurables.with_shifted_offsets(-5).unwrap();
103 let expected_offsets_with_data = vec![Configurable {
104 offset: 5u64,
105 data: vec![4, 5, 6],
106 }];
107 assert_eq!(
108 shifted_configurables.offsets_with_data,
109 expected_offsets_with_data
110 );
111 }
112
113 #[test]
114 fn test_with_shifted_offsets_zero_shift() {
115 let offsets_with_data = vec![Configurable {
116 offset: 20u64,
117 data: vec![7, 8, 9],
118 }];
119 let configurables = Configurables::new(offsets_with_data.clone());
120 let shifted_configurables = configurables.with_shifted_offsets(0).unwrap();
121 let expected_offsets_with_data = offsets_with_data;
122 assert_eq!(
123 shifted_configurables.offsets_with_data,
124 expected_offsets_with_data
125 );
126 }
127
128 #[test]
129 fn test_with_shifted_offsets_overflow() {
130 let offsets_with_data = vec![Configurable {
131 offset: u64::MAX - 1,
132 data: vec![1, 2, 3],
133 }];
134 let configurables = Configurables::new(offsets_with_data);
135 let result = configurables.with_shifted_offsets(10);
136 assert!(result.is_err());
137 if let Err(e) = result {
138 assert!(
139 e.to_string()
140 .contains("Overflow occurred while shifting offset")
141 );
142 }
143 }
144
145 #[test]
146 fn test_with_shifted_offsets_underflow() {
147 let offsets_with_data = vec![Configurable {
148 offset: 5u64,
149 data: vec![4, 5, 6],
150 }];
151 let configurables = Configurables::new(offsets_with_data);
152 let result = configurables.with_shifted_offsets(-10);
153 assert!(result.is_err());
154 if let Err(e) = result {
155 assert!(
156 e.to_string()
157 .contains("Overflow occurred while shifting offset")
158 );
159 }
160 }
161}