use crate::converter::types::{CANFrame, Converter, MQTTPayload};
use bytes::BufMut;
use std::fmt;
#[derive(Debug)]
pub struct IntConverter {
instances: usize, bits: usize,
}
impl IntConverter {
pub fn new(instances: usize, bits: usize) -> Result<IntConverter, String> {
match instances {
1 | 2 | 4 | 8 => {}
_ => {
return Err(format!(
"Invalid instance size, allowed values: 1, 2, 4, 8. got {instances}"
));
}
}
match bits {
8 | 16 | 32 | 64 => {}
_ => {
return Err(format!(
"Invalid bit size, allowed values: 8, 16, 32, 64. got {bits}"
));
}
}
if (bits / 8) * instances > 8 {
return Err(format!(
"{instances} instances of {bits} exceed a CAN-Frame (8 byte)"
));
}
Ok(IntConverter { instances, bits })
}
fn expected_len(self: &IntConverter) -> usize {
(self.bits / 8) * self.instances
}
}
impl Converter for IntConverter {
fn towards_mqtt(self: &IntConverter, cf: CANFrame) -> Result<MQTTPayload, String> {
if cf.len() != self.expected_len() {
return Err(format!(
"Length mismatch, expected {} bytes, got {} bytes",
self.expected_len(),
cf.len()
));
}
let bytesize = self.bits / 8;
let mut r: Vec<i64> = vec![];
match self.bits {
8 => {
for i in 0..self.instances {
r.push(i64::from(i8::from_le_bytes(
cf[bytesize * i..bytesize * (i + 1)].try_into().unwrap(),
)));
}
}
16 => {
for i in 0..self.instances {
r.push(i64::from(i16::from_le_bytes(
cf[bytesize * i..bytesize * (i + 1)].try_into().unwrap(),
)));
}
}
32 => {
for i in 0..self.instances {
r.push(i64::from(i32::from_le_bytes(
cf[bytesize * i..bytesize * (i + 1)].try_into().unwrap(),
)));
}
}
_ => {
for i in 0..self.instances {
r.push(i64::from_le_bytes(
cf[bytesize * i..bytesize * (i + 1)].try_into().unwrap(),
));
}
}
}
let res = r
.iter()
.map(|i| format!("{}", *i))
.collect::<Vec<String>>()
.join(" ");
Ok(MQTTPayload::from(res))
}
fn towards_can(self: &IntConverter, msg: MQTTPayload) -> Result<CANFrame, String> {
if !msg.is_ascii() {
return Err(("input contains non-ASCII characters").to_string());
}
let str = msg.escape_ascii().to_string();
let number_strs = str.split(" ").collect::<Vec<_>>();
if number_strs.len() != self.instances {
return Err(format!(
"Wrong amount of instances, expected {}, got {}",
self.instances,
number_strs.len()
));
}
let mut numbers: Vec<u8> = vec![];
match self.bits {
8 => {
for str in number_strs {
match str.parse::<i8>() {
Ok(i) => numbers.put_i8(i),
Err(e) => return Err(format!("Error parsing number: {e}")),
}
}
}
16 => {
for str in number_strs {
match str.parse::<i16>() {
Ok(i) => numbers.put_i16_le(i),
Err(e) => return Err(format!("Error parsing number: {e}")),
}
}
}
32 => {
for str in number_strs {
match str.parse::<i32>() {
Ok(i) => numbers.put_i32_le(i),
Err(e) => return Err(format!("Error parsing number: {e}")),
}
}
}
_ => {
for str in number_strs {
match str.parse::<i64>() {
Ok(i) => numbers.put_i64_le(i),
Err(e) => return Err(format!("Error parsing number: {e}")),
}
}
}
}
match CANFrame::try_new(&numbers[0..self.expected_len()]) {
Ok(cf) => Ok(cf),
Err(e) => Err(e.to_string()),
}
}
}
impl fmt::Display for IntConverter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let instance_string = match self.instances {
1 => "".to_string(),
i => format!("{i}"),
};
write!(f, "{}int{}2ascii", instance_string, self.bits)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new() {
IntConverter::new(1, 8).expect("should not err, 1*8 fits");
IntConverter::new(2, 8).expect("should not err, 2*8 fits");
IntConverter::new(4, 8).expect("should not err, 4*8 fits");
IntConverter::new(8, 8).expect("should not err, 8*8 fits");
IntConverter::new(1, 16).expect("should not err, 1*16 fits");
IntConverter::new(2, 16).expect("should not err, 2*16 fits");
IntConverter::new(4, 16).expect("should not err, 4*16 fits");
IntConverter::new(1, 32).expect("should not err, 1*32 fits");
IntConverter::new(2, 32).expect("should not err, 2*32 fits");
IntConverter::new(1, 64).expect("should not err, 1*64 fits");
IntConverter::new(3, 8).expect_err("should err, 3 is no valid instance count");
IntConverter::new(1, 7).expect_err("should err, 7 is no valid bit count");
IntConverter::new(2, 64).expect_err("should err, 2*64 exceeds CAN Frame size of 8 byte");
}
#[test]
fn test_name() {
assert_eq!(IntConverter::new(1, 8).unwrap().to_string(), "int82ascii");
assert_eq!(IntConverter::new(2, 8).unwrap().to_string(), "2int82ascii");
assert_eq!(
IntConverter::new(2, 32).unwrap().to_string(),
"2int322ascii"
);
}
#[test]
fn test_towards_mqtt18() {
let cv = IntConverter::new(1, 8).unwrap();
let cf = CANFrame::new([1]);
assert_eq!(cv.towards_mqtt(cf).unwrap(), "1");
}
#[test]
fn test_towards_mqtt28() {
let cv = IntConverter::new(2, 8).unwrap();
let cf = CANFrame::new([1, 2]);
assert_eq!(cv.towards_mqtt(cf).unwrap(), "1 2");
}
#[test]
fn test_towards_mqtt28e() {
let cv = IntConverter::new(2, 8).unwrap();
let cf = CANFrame::new([1, 2, 3]);
cv.towards_mqtt(cf).expect_err("should err, wrong length");
}
#[test]
fn test_towards_mqtt416() {
let cv = IntConverter::new(4, 16).unwrap();
let cf = CANFrame::new([1, 0, 2, 0, 3, 0, 5, 0]);
assert_eq!(cv.towards_mqtt(cf).unwrap(), "1 2 3 5");
}
#[test]
fn test_towards_mqtt232() {
let cv = IntConverter::new(2, 32).unwrap();
let cf = CANFrame::new([1, 0, 0, 0, 2, 0, 0, 0]);
assert_eq!(cv.towards_mqtt(cf).unwrap(), "1 2");
}
#[test]
fn test_towards_can88() {
let cv = IntConverter::new(8, 8).unwrap();
let msg = MQTTPayload::copy_from_slice("4 2 3 4 5 6 7 8".as_bytes());
let cf = cv.towards_can(msg).unwrap();
assert_eq!(cf, [4, 2, 3, 4, 5, 6, 7, 8]);
}
#[test]
fn test_towards_can88e() {
let cv = IntConverter::new(8, 8).unwrap();
let msg = MQTTPayload::copy_from_slice("128 2 3 4 5 6 7 8".as_bytes());
cv.towards_can(msg)
.expect_err("should err, 128 too large for a i8");
}
#[test]
fn test_towards_can88e2() {
let cv = IntConverter::new(8, 8).unwrap();
let msg = MQTTPayload::copy_from_slice("-1 2 3 4 5 6 7 8".as_bytes());
let mut expected_res: Vec<u8> = vec![];
expected_res.put_i8(-1);
expected_res.put_i8(2);
expected_res.put_i8(3);
expected_res.put_i8(4);
expected_res.put_i8(5);
expected_res.put_i8(6);
expected_res.put_i8(7);
expected_res.put_i8(8);
assert_eq!(expected_res[0..8], cv.towards_can(msg).unwrap());
}
#[test]
fn test_towards_can88e22() {
let cv = IntConverter::new(8, 8).unwrap();
let msg = MQTTPayload::copy_from_slice("-128 -129 3 4 5 6 7 8".as_bytes());
cv.towards_can(msg)
.expect_err("should err, -129 too large for a i8");
}
#[test]
fn test_towards_can88e3() {
let cv = IntConverter::new(8, 8).unwrap();
let msg = MQTTPayload::copy_from_slice("2 3 4 5 6 7 8".as_bytes());
cv.towards_can(msg)
.expect_err("should err, too few instances");
}
#[test]
fn test_towards_can88e4() {
let cv = IntConverter::new(8, 8).unwrap();
let msg = MQTTPayload::copy_from_slice("1 1 2 3 4 5 6 7 8".as_bytes());
cv.towards_can(msg)
.expect_err("should err, too many instances");
}
#[test]
fn test_towards_can88e5() {
let cv = IntConverter::new(8, 8).unwrap();
let msg = MQTTPayload::copy_from_slice("a 2 3 4 5 6 7 8".as_bytes());
cv.towards_can(msg)
.expect_err("should err, non-numbers involved");
}
#[test]
fn test_towards_can416() {
let cv = IntConverter::new(4, 16).unwrap();
let msg = MQTTPayload::copy_from_slice("1 2 3 4".as_bytes());
let cf = cv.towards_can(msg).unwrap();
assert_eq!(cf, [1, 0, 2, 0, 3, 0, 4, 0]);
}
#[test]
fn test_towards_can216() {
let cv = IntConverter::new(2, 16).unwrap();
let msg = MQTTPayload::copy_from_slice("1 2".as_bytes());
let cf = cv.towards_can(msg).unwrap();
assert_eq!(cf, [1, 0, 2, 0]);
}
}