1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use std::fmt::Debug;

use either::Either;
use tokio_modbus::{Address, Quantity};

pub(crate) trait Span {
  fn address(&self) -> Address;

  fn quantity(&self) -> Quantity;
}

pub(crate) trait SpanParser<TParsed: Span> {
  #[allow(dead_code, reason = "keep it just in case")]
  fn parse<TIterator, TIntoIterator>(
    &self,
    data: TIntoIterator,
  ) -> anyhow::Result<TParsed>
  where
    TIterator: DoubleEndedIterator<Item = u16>,
    TIntoIterator: IntoIterator<Item = u16, IntoIter = TIterator>;

  fn parse_with_timestamp<TIterator, TIntoIterator>(
    &self,
    data: TIntoIterator,
    timestamp: chrono::DateTime<chrono::Utc>,
  ) -> anyhow::Result<TParsed>
  where
    TIterator: DoubleEndedIterator<Item = u16>,
    TIntoIterator: IntoIterator<Item = u16, IntoIter = TIterator>;
}

#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub(crate) struct SimpleSpan {
  pub(crate) address: u16,
  pub(crate) quantity: u16,
}

impl Span for SimpleSpan {
  fn address(&self) -> Address {
    self.address
  }

  fn quantity(&self) -> Quantity {
    self.quantity
  }
}

impl<TLeftSpan: Span, TRightSpan: Span> Span for Either<TLeftSpan, TRightSpan> {
  fn address(&self) -> Address {
    match self {
      Either::Left(span) => span.address(),
      Either::Right(span) => span.address(),
    }
  }

  fn quantity(&self) -> Quantity {
    match self {
      Either::Left(span) => span.quantity(),
      Either::Right(span) => span.quantity(),
    }
  }
}

impl<
    TLeftSpan: Span,
    TLeftSpanParser: SpanParser<TLeftSpan>,
    TRightSpan: Span,
    TRightSpanParser: SpanParser<TRightSpan>,
  > SpanParser<Either<TLeftSpan, TRightSpan>>
  for Either<TLeftSpanParser, TRightSpanParser>
{
  fn parse<TIterator, TIntoIterator>(
    &self,
    data: TIntoIterator,
  ) -> anyhow::Result<Either<TLeftSpan, TRightSpan>>
  where
    TIterator: DoubleEndedIterator<Item = u16>,
    TIntoIterator: IntoIterator<Item = u16, IntoIter = TIterator>,
  {
    match self {
      Either::Left(parser) => Ok(Either::Left(parser.parse(data)?)),
      Either::Right(parser) => Ok(Either::Right(parser.parse(data)?)),
    }
  }

  fn parse_with_timestamp<TIterator, TIntoIterator>(
    &self,
    data: TIntoIterator,
    timestamp: chrono::DateTime<chrono::Utc>,
  ) -> anyhow::Result<Either<TLeftSpan, TRightSpan>>
  where
    TIterator: DoubleEndedIterator<Item = u16>,
    TIntoIterator: IntoIterator<Item = u16, IntoIter = TIterator>,
  {
    match self {
      Either::Left(parser) => {
        Ok(Either::Left(parser.parse_with_timestamp(data, timestamp)?))
      }
      Either::Right(parser) => {
        Ok(Either::Right(parser.parse_with_timestamp(data, timestamp)?))
      }
    }
  }
}