From 6230817405aa2693c65f81042d50bb58198a9cab Mon Sep 17 00:00:00 2001 From: Hlars Date: Fri, 22 Oct 2021 17:59:36 +0200 Subject: [PATCH] error implementation --- src/errors.rs | 48 +++++++++++++++++++++++++++++++++++++++++--- src/sps_datatypes.rs | 32 +++++++++++++++++++++++++++++ src/types/boolean.rs | 19 ++++++++++++++---- src/types/dint.rs | 14 +++++++------ src/types/int.rs | 14 +++++++------ src/types/real.rs | 14 +++++++------ src/types/string.rs | 18 +++++++++-------- src/types/time.rs | 12 ++++++----- src/types/udint.rs | 14 +++++++------ src/types/uint.rs | 14 +++++++------ 10 files changed, 149 insertions(+), 50 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index f7bffc7..ae344b2 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,48 @@ -use anyhow::{anyhow, Error}; +use std::fmt; +use std::error::Error; +use anyhow::{anyhow}; -pub fn serial_error(name: String, pos: u32) -> Error { +#[derive(Debug)] +pub enum Errors { + MissingBit, + InvalidBit, + MissingLength, + InvalidLength, + UnknownType, + ConversionError{ + byte: u32, + type_string: String, + } +} + +impl Errors { + fn conversion(&self) -> &str { + match self { + Self::MissingBit => "Missing bit position.", + Self::InvalidBit => "Invalid value for bit. Expecting u8 between 0 and 7.", + Self::MissingLength => "Missing data length.", + Self::InvalidLength => "Invalid value for data_length in DBItem. Expecting u32.", + Self::UnknownType => "Unknown datatype", + Self::ConversionError{byte: _, type_string: _} => "Cannot convert data into type.", + } + } +} + +impl fmt::Display for Errors { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let err_msg = self.conversion(); + + write!(f, "{}", err_msg) + } +} + +impl Error for Errors { + fn description(&self) -> &str { + self.conversion() + } +} + +pub fn serial_error(name: String, pos: u32) -> anyhow::Error { anyhow!( "Cannot convert Serial data for type '{}' at position {}.", name, @@ -8,6 +50,6 @@ pub fn serial_error(name: String, pos: u32) -> Error { ) } -pub fn s7_read_error(name: String, pos: u32) -> Error { +pub fn s7_read_error(name: String, pos: u32) -> anyhow::Error { anyhow!("Cannot read Byte for type '{}' at position {}.", name, pos) } diff --git a/src/sps_datatypes.rs b/src/sps_datatypes.rs index 3f53fec..b652b10 100644 --- a/src/sps_datatypes.rs +++ b/src/sps_datatypes.rs @@ -7,10 +7,19 @@ use super::types::string::*; use super::types::time::*; use super::types::udint::*; use super::types::uint::*; +use super::errors::Errors; use serde::{Deserialize, Serialize}; +use std::convert::TryFrom; use anyhow::Result; +pub struct DataInfo { + pub type_string: String, + pub byte: u32, + pub length: Option, + pub bit: Option, +} + #[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub enum SPSDataTypes { Boolean(BooleanType), @@ -24,6 +33,29 @@ pub enum SPSDataTypes { String(StringType), } +impl TryFrom for SPSDataTypes { + type Error = Errors; + + fn try_from(data: DataInfo) -> Result { + match data.type_string.to_lowercase().as_str() { + "boolean" => Ok(Self::Boolean(BooleanType::new(data.byte, data.bit)?)), + "int" => Ok(Self::Int(IntType::new(data.byte, data.bit)?)), + "dint" => Ok(Self::DInt(DIntType::new(data.byte, data.bit)?)), + "real" => Ok(Self::Real(RealType::new(data.byte, data.bit)?)), + "time" => Ok(Self::Time(TimeType::new(data.byte, data.bit)?)), + "udint" => Ok(Self::UDInt(UDIntType::new(data.byte, data.bit)?)), + "uint" => Ok(Self::UInt(UIntType::new(data.byte, data.bit)?)), + "string" => { + match data.length { + Some(number) => Ok(Self::String(StringType::new(number, data.byte, data.bit)?)), + None => Err(Errors::MissingLength) + } + } + _ => Err(Errors::UnknownType) + } + } +} + impl SPSDataTypes { fn into(self) -> Box { match self { diff --git a/src/types/boolean.rs b/src/types/boolean.rs index ebb411b..e510034 100644 --- a/src/types/boolean.rs +++ b/src/types/boolean.rs @@ -11,9 +11,20 @@ pub struct BooleanType { } impl BooleanType { - pub fn new(byte: u32, bit: Option) -> Self { - BooleanType { - position: BitPosition { byte, bit }, + pub fn new(byte: u32, bit: Option) -> Result { + match bit { + Some(bit_) => { + if bit_ < 8 { + Ok( + BooleanType { + position: BitPosition { byte, bit }, + } + ) + } else { + Err(Errors::InvalidBit) + } + }, + None => Err(Errors::MissingBit) } } fn into_string(self) -> String { @@ -74,7 +85,7 @@ fn test() { const BITPOS: u32 = 4; const VAL: bool = false; - let test_item = BooleanType::new(BYTEPOS, Some(BITPOS)); + let test_item = BooleanType::new(BYTEPOS, Some(BITPOS)).unwrap(); let raw_data: [u8; 50] = [0; 50]; let mut test_vec: Vec = raw_data.to_vec(); diff --git a/src/types/dint.rs b/src/types/dint.rs index 1819208..7d485c4 100644 --- a/src/types/dint.rs +++ b/src/types/dint.rs @@ -13,11 +13,13 @@ pub struct DIntType { impl DIntType { const LEN: usize = 4; - pub fn new(byte: u32, bit: Option) -> Self { - DIntType { - length: Self::LEN as u32, - position: BitPosition { byte, bit }, - } + pub fn new(byte: u32, bit: Option) -> Result { + Ok( + DIntType { + length: Self::LEN as u32, + position: BitPosition { byte, bit }, + } + ) } fn into_string(self) -> String { @@ -69,7 +71,7 @@ fn test() { const INTPOS: u32 = 5; const INT: i32 = -2589090; const LEN: usize = 4; - let test_item = DIntType::new(INTPOS, None); + let test_item = DIntType::new(INTPOS, None).unwrap(); let raw_data: [u8; 50] = [255; 50]; let mut test_vec: Vec = raw_data.to_vec(); test_vec.splice( diff --git a/src/types/int.rs b/src/types/int.rs index 0a32a22..13c130e 100644 --- a/src/types/int.rs +++ b/src/types/int.rs @@ -12,11 +12,13 @@ pub struct IntType { impl IntType { const LEN: usize = 2; - pub fn new(byte: u32, bit: Option) -> Self { - IntType { - length: Self::LEN as u32, - position: BitPosition { byte, bit }, - } + pub fn new(byte: u32, bit: Option) -> Result { + Ok( + IntType { + length: Self::LEN as u32, + position: BitPosition { byte, bit }, + } + ) } fn into_string(self) -> String { "int".to_string() @@ -67,7 +69,7 @@ fn test() { const INTPOS: u32 = 3; const INT: i16 = -12; const LEN: usize = 2; - let test_item = IntType::new(INTPOS, None); + let test_item = IntType::new(INTPOS, None).unwrap(); let raw_data: [u8; 50] = [255; 50]; let mut test_vec: Vec = raw_data.to_vec(); test_vec.splice( diff --git a/src/types/real.rs b/src/types/real.rs index bf6d8bf..41e3865 100644 --- a/src/types/real.rs +++ b/src/types/real.rs @@ -12,11 +12,13 @@ pub struct RealType { impl RealType { const LEN: usize = 4; - pub fn new(byte: u32, bit: Option) -> Self { - RealType { - length: Self::LEN as u32, - position: BitPosition { byte, bit }, - } + pub fn new(byte: u32, bit: Option) -> Result { + Ok( + RealType { + length: Self::LEN as u32, + position: BitPosition { byte, bit }, + } + ) } fn into_string(self) -> String { "real".to_string() @@ -67,7 +69,7 @@ fn test() { const INTPOS: u32 = 5; const INT: f32 = 2.522529; const LEN: usize = 4; - let test_item = RealType::new(INTPOS, None); + let test_item = RealType::new(INTPOS, None).unwrap(); let raw_data: [u8; 50] = [255; 50]; let mut test_vec: Vec = raw_data.to_vec(); test_vec.splice( diff --git a/src/types/string.rs b/src/types/string.rs index 7f6a499..20a367d 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -10,11 +10,13 @@ pub struct StringType { position: BitPosition, } impl StringType { - pub fn new(length: u32, byte: u32, bit: Option) -> Self { - StringType { - length, - position: BitPosition { byte, bit }, - } + 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() @@ -42,7 +44,7 @@ impl DataEvaluation for StringType { fn parse_serial(&self, data: &[&str]) -> Result { Ok(data .get((self.position.byte) as usize) - .ok_or_else(|| serial_error(self.into_string(), self.position.byte))? + .ok_or(Errors::ConversionError{type_string: self.into_string(), byte: self.position.byte})? .to_string()) } fn parse_s7(&self, data: &[u8]) -> Result { @@ -51,7 +53,7 @@ impl DataEvaluation for StringType { // Byte 3: 1. Nutzzeichen let bytes = data .get((self.position.byte) as usize..(self.position.byte + self.length) as usize) - .ok_or_else(|| s7_read_error(self.into_string(), self.position.byte))?; + .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!( @@ -74,7 +76,7 @@ fn test() { const LEN: u32 = 20; const VAL: &str = "ich bin ein pfau"; - let test_item = StringType::new(LEN + 2, BYTEPOS, None); + 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; diff --git a/src/types/time.rs b/src/types/time.rs index d8dc4b7..e4238d1 100644 --- a/src/types/time.rs +++ b/src/types/time.rs @@ -11,11 +11,13 @@ pub struct TimeType { } impl TimeType { const LEN: usize = 4; - pub fn new(byte: u32, bit: Option) -> Self { - TimeType { - length: Self::LEN as u32, - position: BitPosition { byte, bit }, - } + pub fn new(byte: u32, bit: Option) -> Result { + Ok( + TimeType { + length: Self::LEN as u32, + position: BitPosition { byte, bit }, + } + ) } fn into_string(self) -> String { "time".to_string() diff --git a/src/types/udint.rs b/src/types/udint.rs index f296675..561168f 100644 --- a/src/types/udint.rs +++ b/src/types/udint.rs @@ -11,11 +11,13 @@ pub struct UDIntType { } impl UDIntType { const LEN: usize = 4; - pub fn new(byte: u32, bit: Option) -> Self { - UDIntType { - length: Self::LEN as u32, - position: BitPosition { byte, bit }, - } + pub fn new(byte: u32, bit: Option) -> Result { + Ok( + UDIntType { + length: Self::LEN as u32, + position: BitPosition { byte, bit }, + } + ) } fn into_string(self) -> String { "udint".to_string() @@ -65,7 +67,7 @@ fn test() { const INTPOS: u32 = 5; const INT: u32 = 25890920; const LEN: usize = 4; - let test_item = UDIntType::new(INTPOS, None); + let test_item = UDIntType::new(INTPOS, None).unwrap(); let raw_data: [u8; 50] = [255; 50]; let mut test_vec: Vec = raw_data.to_vec(); test_vec.splice( diff --git a/src/types/uint.rs b/src/types/uint.rs index 8d04f6a..ab66f96 100644 --- a/src/types/uint.rs +++ b/src/types/uint.rs @@ -11,11 +11,13 @@ pub struct UIntType { } impl UIntType { const LEN: usize = 2; - pub fn new(byte: u32, bit: Option) -> Self { - UIntType { - length: Self::LEN as u32, - position: BitPosition { byte, bit }, - } + pub fn new(byte: u32, bit: Option) -> Result { + Ok( + UIntType { + length: Self::LEN as u32, + position: BitPosition { byte, bit }, + } + ) } fn into_string(self) -> String { "uint".to_string() @@ -65,7 +67,7 @@ fn test() { const INTPOS: u32 = 15; const INT: u16 = 8209; const LEN: usize = 2; - let test_item = UIntType::new(INTPOS, None); + let test_item = UIntType::new(INTPOS, None).unwrap(); let raw_data: [u8; 50] = [255; 50]; let mut test_vec: Vec = raw_data.to_vec(); test_vec.splice(