use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; use super::super::errors::*; use super::super::sps_datatypes::{BitPosition, DataEvaluation, UnparsedSPSDataType}; #[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub struct StringType { length: u32, position: BitPosition, } impl StringType { pub fn new(length: u32, byte: u32, bit: Option) -> Result { Ok( StringType { length, position: BitPosition { byte, bit }, } ) } fn into_string(self) -> String { "string".to_string() } } impl DataEvaluation for StringType { fn into_unparsed(&self) -> UnparsedSPSDataType { UnparsedSPSDataType { data_type: self.into_string(), data_byte: self.position.byte, data_bit: self.position.bit, data_length: Some(self.length), } } fn get_end_byte(&self) -> u32 { // first two bytes are header bytes self.position.byte + self.length + 2 } fn get_byte_positon(&self) -> u32 { self.position.byte } fn get_length(&self) -> u32 { self.length } fn parse_serial(&self, data: &[&str]) -> Result { Ok(data .get((self.position.byte) as usize) .ok_or(Errors::ConversionError{type_string: self.into_string(), byte: self.position.byte})? .to_string()) } fn parse_s7(&self, data: &[u8]) -> Result { // Headerbyte 1: Reservierte Stringlänge in Byte [0…254] // Headerbyte 2: Anzahl der zu interpretierenden Zeichen im String ab Byte 3 // Byte 3: 1. Nutzzeichen let bytes = data .get((self.position.byte) as usize..(self.position.byte + self.length) as usize) .ok_or(Errors::ConversionError{type_string: self.into_string(), byte: self.position.byte})?; match String::from_utf8(bytes[2..bytes[1] as usize + 2].to_vec()) { Ok(string) => Ok(string), Err(err) => Err(anyhow!( "Could not convert data at byte {} with length {} into string: {}.", self.position.byte, self.length, err )), } } fn sql_equivalent(&self) -> &str { r"VARCHAR(255)" } } #[test] fn test() { const BYTEPOS: u32 = 5; const LEN: u32 = 20; const VAL: &str = "ich bin ein pfau"; let test_item = StringType::new(LEN + 2, BYTEPOS, None).unwrap(); let raw_data: [u8; 50] = [0; 50]; let mut test_vec: Vec = raw_data.to_vec(); test_vec[BYTEPOS as usize] = LEN as u8 + 2; test_vec[BYTEPOS as usize + 1] = VAL.len() as u8; test_vec.splice( BYTEPOS as usize + 2..BYTEPOS as usize + LEN as usize, VAL.as_bytes().iter().cloned(), ); let result = match test_item.parse_s7(&test_vec) { Ok(res) => res, Err(_) => "Error".to_string(), }; assert_eq!(result, VAL.to_string()) }