1use super::error::Error;
8use byteorder::{BigEndian, ByteOrder};
9
10pub type Fields = Vec<Box<dyn Field>>;
32
33pub trait Field {
36 fn data_block(&self) -> i32;
38 fn offset(&self) -> i32;
42
43 fn to_bytes(&self) -> Vec<u8>;
44}
45
46#[derive(Debug)]
48pub struct Float {
49 data_block: i32,
50 offset: f32,
54 value: f32,
55}
56
57impl Float {
58 pub fn new(data_block: i32, offset: f32, mut bytes: Vec<u8>) -> Result<Float, Error> {
59 let len = bytes.len();
60 if bytes.len() != Float::size() as usize {
61 return Err(Error::TryFrom(
62 bytes,
63 format!("Float.new: expected buf size {} got {}", Float::size(), len),
64 ));
65 }
66
67 let bit_offset = ((offset * 10.0) as usize % 10) as u8;
68 if bit_offset != 0 {
69 return Err(Error::TryFrom(
70 bytes,
71 format!(
72 "Float.new: float should not have a bit offset got {}",
73 bit_offset
74 ),
75 ));
76 }
77
78 Ok(Float {
79 data_block,
80 offset,
81 value: BigEndian::read_f32(bytes.as_mut_slice()),
82 })
83 }
84
85 pub fn size() -> i32 {
86 4
87 }
88
89 pub fn value(&self) -> f32 {
90 self.value
91 }
92
93 pub fn set_value(&mut self, v: f32) {
94 self.value = v
95 }
96}
97
98impl Field for Float {
99 fn data_block(&self) -> i32 {
100 self.data_block
101 }
102
103 fn offset(&self) -> i32 {
104 self.offset as i32
105 }
106
107 fn to_bytes(&self) -> Vec<u8> {
108 let mut buf = vec![0u8; Float::size() as usize];
109 BigEndian::write_f32(buf.as_mut_slice(), self.value);
110 return buf;
111 }
112}
113
114#[derive(Debug)]
116pub struct Bool {
117 data_block: i32,
119 offset: f32,
123 byte: u8,
125 value: bool,
127}
128
129impl Bool {
130 pub fn new(data_block: i32, offset: f32, bytes: Vec<u8>) -> Result<Self, Error> {
131 let len = bytes.len();
132 if bytes.len() != Self::size() as usize {
133 return Err(Error::TryFrom(
134 bytes,
135 format!("Bool.new: expected buf size {} got {}", Self::size(), len),
136 ));
137 }
138
139 let bit_offset = ((offset * 10.0) as usize % 10) as u8;
140 if bit_offset > 7 {
141 return Err(Error::TryFrom(
142 bytes,
143 format!("Bool.new: max offset is 7 got {}", offset),
144 ));
145 }
146
147 Ok(Bool {
148 data_block,
149 offset,
150 byte: bytes[0],
151 value: bytes[0] & (1 << bit_offset) != 0,
152 })
153 }
154
155 #[inline(always)]
156 fn set_value_at(b: u8, bit_pos: u8, val: bool) -> u8 {
157 if val {
158 return b | (1 << bit_pos);
159 }
160 return b & !(1 << bit_pos);
161 }
162
163 pub fn size() -> i32 {
164 1
165 }
166
167 pub fn value(&self) -> bool {
169 self.value
170 }
171
172 pub fn set_value(&mut self, v: bool) {
173 self.value = v;
174 self.byte = Bool::set_value_at(
175 self.byte,
176 ((self.offset * 10.0) as usize % 10) as u8,
177 self.value,
178 );
179 }
180}
181
182impl Field for Bool {
183 fn data_block(&self) -> i32 {
184 self.data_block
185 }
186
187 fn offset(&self) -> i32 {
188 self.offset as i32
189 }
190
191 fn to_bytes(&self) -> Vec<u8> {
192 vec![self.byte]
193 }
194}
195
196#[test]
197fn test_fields() {
198 let float = Float::new(888, 8.0, vec![66, 86, 0, 0]).unwrap();
199 let boolean = Bool::new(888, 8.0, vec![1u8]).unwrap();
200 assert!(boolean.value());
201 assert_eq!(53.5, float.value());
202 let fields: Fields = vec![Box::new(float), Box::new(boolean)];
203
204 for field in fields.iter() {
205 println!(
206 "saving bytes {:?} to block {} offset {}",
207 field.to_bytes(),
208 field.data_block(),
209 field.offset()
210 )
211 }
212}
213
214#[test]
215fn test_float() {
216 let val: f32 = 53.5;
217 let mut b = vec![0u8; Float::size() as usize];
218 BigEndian::write_f32(b.as_mut_slice(), val);
219 let mut field = Float::new(888, 8.0, b).unwrap();
220 field.set_value(val);
221 let result = field.to_bytes();
222
223 assert_eq!(vec![66, 86, 0, 0], result);
224
225 match Float::new(888, 8.1, vec![66, 86, 0, 0]) {
228 Ok(_) => {
229 println!("should return an error at invalid bit offset 1. Floats should not have a bit offset");
230 assert!(false)
231 }
232 Err(_) => {}
233 }
234}
235
236#[test]
237fn test_bool() {
238 let b = vec![1u8; 1];
239 let mut field = Bool::new(888, 8.1, b).unwrap();
240 field.set_value(true);
241
242 let mut res: Vec<u8> = field.to_bytes();
243
244 assert_eq!(res.len(), 1);
245 assert_eq!(res[0], 3);
246 assert_eq!(field.value(), true);
247
248 field.set_value(false);
249 res = field.to_bytes();
250
251 assert_eq!(res.len(), 1);
252 assert_eq!(res[0], 1);
253 assert_eq!(field.value(), false);
254
255 let bb = vec![0b00001000u8; 1];
256 field = Bool::new(888, 8.4, bb).unwrap();
257 field.set_value(true);
258
259 res = field.to_bytes();
260
261 assert_eq!(res.len(), 1);
262 assert_eq!(res[0], 24);
263 assert_eq!(field.value(), true);
264
265 match Bool::new(888, 8.8, vec![0b00001000u8; 1]) {
267 Ok(_) => {
268 println!("should return an error at invalid bit offset 8");
269 assert!(false)
270 }
271 Err(_) => {}
272 }
273}