use std::{
cmp::Ordering::{self, Equal, Greater, Less},
hash::Hasher,
};
use crate::{
datagram::Datagram, header::Header, id_hash::IdHash, packet::Packet, telegram::Telegram,
};
#[derive(Clone, Debug)]
pub enum Data {
Packet(Packet),
Datagram(Datagram),
Telegram(Telegram),
}
impl Data {
pub fn is_packet(&self) -> bool {
matches!(*self, Data::Packet(_))
}
pub fn is_datagram(&self) -> bool {
matches!(*self, Data::Datagram(_))
}
pub fn is_telegram(&self) -> bool {
matches!(*self, Data::Telegram(_))
}
pub fn into_packet(self) -> Packet {
match self {
Data::Packet(packet) => packet,
_ => panic!(
"called `Data::into_packet` for a non-`Packet` value: {:?}",
self
),
}
}
pub fn into_datagram(self) -> Datagram {
match self {
Data::Datagram(datagram) => datagram,
_ => panic!(
"called `Data::into_datagram` for a non-`Datagram` value: {:?}",
self
),
}
}
pub fn into_telegram(self) -> Telegram {
match self {
Data::Telegram(telegram) => telegram,
_ => panic!(
"called `Data::into_telegram` for a non-`Telegram` value: {:?}",
self
),
}
}
pub fn as_header(&self) -> &Header {
self.as_ref()
}
pub fn as_packet(&self) -> &Packet {
match *self {
Data::Packet(ref packet) => packet,
_ => panic!(
"called `Data::as_packet` for a non-`Packet` value: {:?}",
self
),
}
}
pub fn as_datagram(&self) -> &Datagram {
match *self {
Data::Datagram(ref datagram) => datagram,
_ => panic!(
"called `Data::as_datagram` for a non-`Datagram` value: {:?}",
self
),
}
}
pub fn as_telegram(&self) -> &Telegram {
match *self {
Data::Telegram(ref telegram) => telegram,
_ => panic!(
"called `Data::as_telegram` for a non-`Telegram` value: {:?}",
self
),
}
}
pub fn id_string(&self) -> String {
match *self {
Data::Packet(ref packet) => packet.id_string(),
Data::Datagram(ref dgram) => dgram.id_string(),
Data::Telegram(ref tgram) => tgram.id_string(),
}
}
}
impl IdHash for Data {
fn id_hash<H: Hasher>(&self, h: &mut H) {
match *self {
Data::Packet(ref packet) => packet.id_hash(h),
Data::Datagram(ref dgram) => dgram.id_hash(h),
Data::Telegram(ref tgram) => tgram.id_hash(h),
}
}
}
impl PartialEq for Data {
fn eq(&self, right: &Data) -> bool {
let left = self;
let left_header = left.as_header();
let right_header = right.as_header();
if left_header.channel != right_header.channel {
false
} else if left_header.destination_address != right_header.destination_address {
false
} else if left_header.source_address != right_header.source_address {
false
} else if left_header.protocol_version != right_header.protocol_version {
false
} else {
match *left {
Data::Packet(ref left_packet) => {
if let Data::Packet(ref right_packet) = *right {
if left_packet.command != right_packet.command {
false
} else {
true
}
} else {
false
}
}
Data::Datagram(ref left_dgram) => {
if let Data::Datagram(ref right_dgram) = *right {
if left_dgram.command != right_dgram.command {
false
} else if left_dgram.command != 0x0900 {
true
} else if left_dgram.param16 != right_dgram.param16 {
false
} else {
true
}
} else {
false
}
}
Data::Telegram(ref left_tgram) => {
if let Data::Telegram(ref right_tgram) = *right {
if left_tgram.command != right_tgram.command {
false
} else {
true
}
} else {
false
}
}
}
}
}
}
impl PartialOrd for Data {
fn partial_cmp(&self, right: &Data) -> Option<Ordering> {
let left = self;
let left_header = left.as_header();
let right_header = right.as_header();
if left_header.channel < right_header.channel {
Some(Less)
} else if left_header.channel > right_header.channel {
Some(Greater)
} else if left_header.destination_address < right_header.destination_address {
Some(Less)
} else if left_header.destination_address > right_header.destination_address {
Some(Greater)
} else if left_header.source_address < right_header.source_address {
Some(Less)
} else if left_header.source_address > right_header.source_address {
Some(Greater)
} else if left_header.protocol_version < right_header.protocol_version {
Some(Less)
} else if left_header.protocol_version > right_header.protocol_version {
Some(Greater)
} else {
match *left {
Data::Packet(ref left_packet) => {
if let Data::Packet(ref right_packet) = *right {
Some(left_packet.command.cmp(&right_packet.command))
} else {
None
}
}
Data::Datagram(ref left_dgram) => {
if let Data::Datagram(ref right_dgram) = *right {
if left_dgram.command < right_dgram.command {
Some(Less)
} else if left_dgram.command > right_dgram.command {
Some(Greater)
} else if left_dgram.command != 0x0900 {
Some(Equal)
} else if left_dgram.param16 < right_dgram.param16 {
Some(Less)
} else if left_dgram.param16 > right_dgram.param16 {
Some(Greater)
} else {
Some(Equal)
}
} else {
None
}
}
Data::Telegram(ref left_tgram) => {
if let Data::Telegram(ref right_tgram) = *right {
Some(left_tgram.command.cmp(&right_tgram.command))
} else {
None
}
}
}
}
}
}
impl From<Packet> for Data {
fn from(packet: Packet) -> Data {
Data::Packet(packet)
}
}
impl From<Datagram> for Data {
fn from(dgram: Datagram) -> Data {
Data::Datagram(dgram)
}
}
impl From<Telegram> for Data {
fn from(tgram: Telegram) -> Data {
Data::Telegram(tgram)
}
}
impl AsRef<Header> for Data {
fn as_ref(&self) -> &Header {
match *self {
Data::Packet(ref packet) => packet.as_ref(),
Data::Datagram(ref dgram) => dgram.as_ref(),
Data::Telegram(ref tgram) => tgram.as_ref(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::{DateTime, TimeZone, Utc};
use crate::{
id_hash::id_hash,
live_data_decoder::data_from_checked_bytes,
test_data::{LIVE_DATA_1, LIVE_TELEGRAM_1},
};
fn packet_data(timestamp: DateTime<Utc>, channel: u8) -> Data {
data_from_checked_bytes(timestamp, channel, &LIVE_DATA_1[0..])
}
fn datagram_data(timestamp: DateTime<Utc>, channel: u8) -> Data {
data_from_checked_bytes(timestamp, channel, &LIVE_DATA_1[352..])
}
fn telegram_data(timestamp: DateTime<Utc>, channel: u8) -> Data {
data_from_checked_bytes(timestamp, channel, &LIVE_TELEGRAM_1[0..])
}
#[test]
fn test_is_packet() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let packet_data = packet_data(timestamp, channel);
assert_eq!(true, packet_data.is_packet());
let dgram_data = datagram_data(timestamp, channel);
assert_eq!(false, dgram_data.is_packet());
let tgram_data = telegram_data(timestamp, channel);
assert_eq!(false, tgram_data.is_packet());
}
#[test]
fn test_is_datagram() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let packet_data = packet_data(timestamp, channel);
assert_eq!(false, packet_data.is_datagram());
let dgram_data = datagram_data(timestamp, channel);
assert_eq!(true, dgram_data.is_datagram());
let tgram_data = telegram_data(timestamp, channel);
assert_eq!(false, tgram_data.is_datagram());
}
#[test]
fn test_is_telegram() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let packet_data = packet_data(timestamp, channel);
assert_eq!(false, packet_data.is_telegram());
let dgram_data = datagram_data(timestamp, channel);
assert_eq!(false, dgram_data.is_telegram());
let tgram_data = telegram_data(timestamp, channel);
assert_eq!(true, tgram_data.is_telegram());
}
#[test]
fn test_into_packet() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let packet_data = packet_data(timestamp, channel);
let packet = packet_data.into_packet();
assert_eq!(timestamp, packet.header.timestamp);
assert_eq!(channel, packet.header.channel);
assert_eq!(0x0010, packet.header.destination_address);
assert_eq!(0x7E11, packet.header.source_address);
assert_eq!(0x10, packet.header.protocol_version);
}
#[test]
#[should_panic]
fn test_into_packet_panic() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let dgram_data = datagram_data(timestamp, channel);
dgram_data.into_packet();
}
#[test]
fn test_into_datagram() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let dgram_data = datagram_data(timestamp, channel);
let dgram = dgram_data.into_datagram();
assert_eq!(timestamp, dgram.header.timestamp);
assert_eq!(channel, dgram.header.channel);
assert_eq!(0x0000, dgram.header.destination_address);
assert_eq!(0x7E11, dgram.header.source_address);
assert_eq!(0x20, dgram.header.protocol_version);
}
#[test]
#[should_panic]
fn test_into_datagram_panic() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let tgram_data = telegram_data(timestamp, channel);
tgram_data.into_datagram();
}
#[test]
fn test_into_telegram() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let tgram_data = telegram_data(timestamp, channel);
let tgram = tgram_data.into_telegram();
assert_eq!(timestamp, tgram.header.timestamp);
assert_eq!(channel, tgram.header.channel);
assert_eq!(0x7771, tgram.header.destination_address);
assert_eq!(0x2011, tgram.header.source_address);
assert_eq!(0x30, tgram.header.protocol_version);
}
#[test]
#[should_panic]
fn test_into_telegram_panic() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let packet_data = packet_data(timestamp, channel);
packet_data.into_telegram();
}
#[test]
fn test_as_header() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let packet_data = packet_data(timestamp, channel);
let header = packet_data.as_header();
assert_eq!(timestamp, header.timestamp);
assert_eq!(channel, header.channel);
assert_eq!(0x0010, header.destination_address);
assert_eq!(0x7E11, header.source_address);
assert_eq!(0x10, header.protocol_version);
let dgram_data = datagram_data(timestamp, channel);
let header = dgram_data.as_header();
assert_eq!(timestamp, header.timestamp);
assert_eq!(channel, header.channel);
assert_eq!(0x0000, header.destination_address);
assert_eq!(0x7E11, header.source_address);
assert_eq!(0x20, header.protocol_version);
let tgram_data = telegram_data(timestamp, channel);
let header = tgram_data.as_header();
assert_eq!(timestamp, header.timestamp);
assert_eq!(channel, header.channel);
assert_eq!(0x7771, header.destination_address);
assert_eq!(0x2011, header.source_address);
assert_eq!(0x30, header.protocol_version);
}
#[test]
fn test_as_packet() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let packet_data = packet_data(timestamp, channel);
packet_data.as_packet();
}
#[test]
#[should_panic]
fn test_as_packet_panic() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let datagram_data = datagram_data(timestamp, channel);
datagram_data.as_packet();
}
#[test]
fn test_as_datagram() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let datagram_data = datagram_data(timestamp, channel);
datagram_data.as_datagram();
}
#[test]
#[should_panic]
fn test_as_datagram_panic() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let telegram_data = telegram_data(timestamp, channel);
telegram_data.as_datagram();
}
#[test]
fn test_as_telegram() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let telegram_data = telegram_data(timestamp, channel);
telegram_data.as_telegram();
}
#[test]
#[should_panic]
fn test_as_telegram_panic() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let packet_data = packet_data(timestamp, channel);
packet_data.as_telegram();
}
#[test]
fn test_eq() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let packet_data = packet_data(timestamp, channel);
let packet = packet_data.clone().into_packet();
let dgram_data = datagram_data(timestamp, channel);
let dgram = dgram_data.clone().into_datagram();
let tgram_data = telegram_data(timestamp, channel);
let tgram = tgram_data.clone().into_telegram();
let other_timestamp = Utc.timestamp(0, 0);
assert_eq!(false, packet_data.eq(&dgram_data));
assert_eq!(false, packet_data.eq(&tgram_data));
assert_eq!(false, dgram_data.eq(&tgram_data));
let other = packet.clone();
assert_eq!(true, Data::Packet(other).eq(&packet_data));
let mut other = packet.clone();
other.header.timestamp = other_timestamp;
assert_eq!(true, Data::Packet(other).eq(&packet_data));
let mut other = packet.clone();
other.header.channel ^= 1;
assert_eq!(false, Data::Packet(other).eq(&packet_data));
let mut other = packet.clone();
other.header.destination_address ^= 1;
assert_eq!(false, Data::Packet(other).eq(&packet_data));
let mut other = packet.clone();
other.header.source_address ^= 1;
assert_eq!(false, Data::Packet(other).eq(&packet_data));
let mut other = packet.clone();
other.header.protocol_version ^= 1;
assert_eq!(false, Data::Packet(other).eq(&packet_data));
let mut other = packet.clone();
other.command ^= 1;
assert_eq!(false, Data::Packet(other).eq(&packet_data));
let mut other = packet.clone();
other.frame_count ^= 1;
assert_eq!(true, Data::Packet(other).eq(&packet_data));
let mut other = packet.clone();
other.frame_data[0] ^= 1;
assert_eq!(true, Data::Packet(other).eq(&packet_data));
let other = dgram.clone();
assert_eq!(true, Data::Datagram(other).eq(&dgram_data));
let mut other = dgram.clone();
other.header.timestamp = other_timestamp;
assert_eq!(true, Data::Datagram(other).eq(&dgram_data));
let mut other = dgram.clone();
other.header.channel ^= 1;
assert_eq!(false, Data::Datagram(other).eq(&dgram_data));
let mut other = dgram.clone();
other.header.destination_address ^= 1;
assert_eq!(false, Data::Datagram(other).eq(&dgram_data));
let mut other = dgram.clone();
other.header.source_address ^= 1;
assert_eq!(false, Data::Datagram(other).eq(&dgram_data));
let mut other = dgram.clone();
other.header.protocol_version ^= 1;
assert_eq!(false, Data::Datagram(other).eq(&dgram_data));
let mut other = dgram.clone();
other.command ^= 1;
assert_eq!(false, Data::Datagram(other).eq(&dgram_data));
let mut other = dgram.clone();
other.param16 ^= 1;
assert_eq!(true, Data::Datagram(other).eq(&dgram_data));
let mut other = dgram.clone();
other.param32 ^= 1;
assert_eq!(true, Data::Datagram(other).eq(&dgram_data));
let other = tgram.clone();
assert_eq!(true, Data::Telegram(other).eq(&tgram_data));
let mut other = tgram.clone();
other.header.timestamp = other_timestamp;
assert_eq!(true, Data::Telegram(other).eq(&tgram_data));
let mut other = tgram.clone();
other.header.channel ^= 1;
assert_eq!(false, Data::Telegram(other).eq(&tgram_data));
let mut other = tgram.clone();
other.header.destination_address ^= 1;
assert_eq!(false, Data::Telegram(other).eq(&tgram_data));
let mut other = tgram.clone();
other.header.source_address ^= 1;
assert_eq!(false, Data::Telegram(other).eq(&tgram_data));
let mut other = tgram.clone();
other.header.protocol_version ^= 1;
assert_eq!(false, Data::Telegram(other).eq(&tgram_data));
let mut other = tgram.clone();
other.command ^= 1;
assert_eq!(false, Data::Telegram(other).eq(&tgram_data));
let mut other = tgram.clone();
other.frame_data[0] ^= 1;
assert_eq!(true, Data::Telegram(other).eq(&tgram_data));
}
#[test]
fn test_partial_cmp() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let packet_data = packet_data(timestamp, channel);
let packet = match packet_data {
Data::Packet(ref packet) => packet,
_ => unreachable!(),
};
let dgram_data = datagram_data(timestamp, channel);
let dgram = match dgram_data {
Data::Datagram(ref dgram) => dgram,
_ => unreachable!(),
};
let tgram_data = telegram_data(timestamp, channel);
let tgram = match tgram_data {
Data::Telegram(ref tgram) => tgram,
_ => unreachable!(),
};
let other_timestamp = Utc.timestamp(0, 0);
assert_eq!(Some(Greater), packet_data.partial_cmp(&dgram_data));
assert_eq!(Some(Less), packet_data.partial_cmp(&tgram_data));
assert_eq!(Some(Less), dgram_data.partial_cmp(&tgram_data));
let other = packet.clone();
assert_eq!(Some(Equal), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.header.timestamp = other_timestamp;
assert_eq!(Some(Equal), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.header.channel -= 1;
assert_eq!(Some(Less), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.header.channel += 1;
assert_eq!(Some(Greater), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.header.destination_address -= 1;
assert_eq!(Some(Less), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.header.destination_address += 1;
assert_eq!(Some(Greater), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.header.source_address -= 1;
assert_eq!(Some(Less), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.header.source_address += 1;
assert_eq!(Some(Greater), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.header.protocol_version -= 1;
assert_eq!(Some(Less), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.header.protocol_version += 1;
assert_eq!(Some(Greater), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.command -= 1;
assert_eq!(Some(Less), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.command += 1;
assert_eq!(Some(Greater), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.frame_count ^= 1;
assert_eq!(Some(Equal), Data::Packet(other).partial_cmp(&packet_data));
let mut other = packet.clone();
other.frame_data[0] ^= 1;
assert_eq!(Some(Equal), Data::Packet(other).partial_cmp(&packet_data));
let other = dgram.clone();
assert_eq!(Some(Equal), Data::Datagram(other).partial_cmp(&dgram_data));
let mut other = dgram.clone();
other.header.timestamp = other_timestamp;
assert_eq!(Some(Equal), Data::Datagram(other).partial_cmp(&dgram_data));
let mut other = dgram.clone();
other.header.channel -= 1;
assert_eq!(Some(Less), Data::Datagram(other).partial_cmp(&dgram_data));
let mut other = dgram.clone();
other.header.channel += 1;
assert_eq!(
Some(Greater),
Data::Datagram(other).partial_cmp(&dgram_data)
);
let mut other = dgram.clone();
other.header.destination_address += 1; assert_eq!(Some(Less), dgram_data.partial_cmp(&Data::Datagram(other)));
let mut other = dgram.clone();
other.header.destination_address += 1;
assert_eq!(
Some(Greater),
Data::Datagram(other).partial_cmp(&dgram_data)
);
let mut other = dgram.clone();
other.header.source_address -= 1;
assert_eq!(Some(Less), Data::Datagram(other).partial_cmp(&dgram_data));
let mut other = dgram.clone();
other.header.source_address += 1;
assert_eq!(
Some(Greater),
Data::Datagram(other).partial_cmp(&dgram_data)
);
let mut other = dgram.clone();
other.header.protocol_version -= 1;
assert_eq!(Some(Less), Data::Datagram(other).partial_cmp(&dgram_data));
let mut other = dgram.clone();
other.header.protocol_version += 1;
assert_eq!(
Some(Greater),
Data::Datagram(other).partial_cmp(&dgram_data)
);
let mut other = dgram.clone();
other.command -= 1;
assert_eq!(Some(Less), Data::Datagram(other).partial_cmp(&dgram_data));
let mut other = dgram.clone();
other.command += 1;
assert_eq!(
Some(Greater),
Data::Datagram(other).partial_cmp(&dgram_data)
);
let mut other = dgram.clone();
other.param16 ^= 1;
assert_eq!(Some(Equal), Data::Datagram(other).partial_cmp(&dgram_data));
let mut other = dgram.clone();
other.param32 ^= 1;
assert_eq!(Some(Equal), Data::Datagram(other).partial_cmp(&dgram_data));
let other = tgram.clone();
assert_eq!(Some(Equal), Data::Telegram(other).partial_cmp(&tgram_data));
let mut other = tgram.clone();
other.header.timestamp = other_timestamp;
assert_eq!(Some(Equal), Data::Telegram(other).partial_cmp(&tgram_data));
let mut other = tgram.clone();
other.header.channel -= 1;
assert_eq!(Some(Less), Data::Telegram(other).partial_cmp(&tgram_data));
let mut other = tgram.clone();
other.header.channel += 1;
assert_eq!(
Some(Greater),
Data::Telegram(other).partial_cmp(&tgram_data)
);
let mut other = tgram.clone();
other.header.destination_address -= 1;
assert_eq!(Some(Less), Data::Telegram(other).partial_cmp(&tgram_data));
let mut other = tgram.clone();
other.header.destination_address += 1;
assert_eq!(
Some(Greater),
Data::Telegram(other).partial_cmp(&tgram_data)
);
let mut other = tgram.clone();
other.header.source_address -= 1;
assert_eq!(Some(Less), Data::Telegram(other).partial_cmp(&tgram_data));
let mut other = tgram.clone();
other.header.source_address += 1;
assert_eq!(
Some(Greater),
Data::Telegram(other).partial_cmp(&tgram_data)
);
let mut other = tgram.clone();
other.header.protocol_version -= 1;
assert_eq!(Some(Less), Data::Telegram(other).partial_cmp(&tgram_data));
let mut other = tgram.clone();
other.header.protocol_version += 1;
assert_eq!(
Some(Greater),
Data::Telegram(other).partial_cmp(&tgram_data)
);
let mut other = tgram.clone();
other.command -= 1;
assert_eq!(Some(Less), Data::Telegram(other).partial_cmp(&tgram_data));
let mut other = tgram.clone();
other.command += 1;
assert_eq!(
Some(Greater),
Data::Telegram(other).partial_cmp(&tgram_data)
);
let mut other = tgram.clone();
other.frame_data[0] ^= 1;
assert_eq!(Some(Equal), Data::Telegram(other).partial_cmp(&tgram_data));
}
#[test]
fn test_id_hash() {
let timestamp = Utc.timestamp(1485688933, 0);
let channel = 0x11;
let data = packet_data(timestamp, channel);
let result = id_hash(&data);
assert_eq!(541127499104566154, result);
let data = datagram_data(timestamp, channel);
let result = id_hash(&data);
assert_eq!(6066488998843577430, result);
let data = telegram_data(timestamp, channel);
let result = id_hash(&data);
assert_eq!(2688669052981416192, result);
}
}