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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
use std::io::{Read, Write};

use encoding::*;
use basic_types::*;
use date_time::*;
use variant::Variant;
use status_codes::StatusCode;
use status_codes::StatusCode::Good;

/// False if the Value is Null.
const HAS_VALUE: u8 = 0x1;
/// False if the StatusCode is Good.
const HAS_STATUS: u8 = 0x2;
/// False if the Source Timestamp is DateTime.MinValue.
const HAS_SOURCE_TIMESTAMP: u8 = 0x4;
/// False if the Server Timestamp is DateTime.MinValue.
const HAS_SERVER_TIMESTAMP: u8 = 0x8;
/// False if the Source Picoseconds is 0.
const HAS_SOURCE_PICOSECONDS: u8 = 0x10;
/// False if the Server Picoseconds is 0.
const HAS_SERVER_PICOSECONDS: u8 = 0x20;

/// Data type ID 23
#[derive(Debug, Clone, PartialEq)]
pub struct DataValue {
    /// The value. BaseDataType
    /// Not present if the Value bit in the EncodingMask is False.
    pub value: Option<Variant>,
    /// The status associated with the value.
    /// Not present if the StatusCode bit in the EncodingMask is False
    pub status: Option<StatusCode>,
    /// The source timestamp associated with the value.
    /// Not present if the SourceTimestamp bit in the EncodingMask is False.
    pub source_timestamp: Option<DateTime>,
    /// The number of 10 picosecond intervals for the SourceTimestamp.
    /// Not present if the SourcePicoSeconds bit in the EncodingMask is False.
    /// If the source timestamp is missing the picoseconds are ignored.
    pub source_picoseconds: Option<Int16>,
    /// The Server timestamp associated with the value.
    /// Not present if the ServerTimestamp bit in the EncodingMask is False.
    pub server_timestamp: Option<DateTime>,
    /// The number of 10 picosecond intervals for the ServerTimestamp.
    /// Not present if the ServerPicoSeconds bit in the EncodingMask is False.
    /// If the Server timestamp is missing the picoseconds are ignored.
    pub server_picoseconds: Option<Int16>,
}

impl BinaryEncoder<DataValue> for DataValue {
    fn byte_len(&self) -> usize {
        let mut size = 1;
        let encoding_mask = self.encoding_mask();
        if encoding_mask & HAS_VALUE != 0 {
            size += self.value.as_ref().unwrap().byte_len();
        }
        if encoding_mask & HAS_STATUS != 0 {
            size += self.status.as_ref().unwrap().byte_len();
        }
        if encoding_mask & HAS_SOURCE_TIMESTAMP != 0 {
            size += self.source_timestamp.as_ref().unwrap().byte_len();
            if encoding_mask & HAS_SOURCE_PICOSECONDS != 0 {
                size += self.source_picoseconds.as_ref().unwrap().byte_len();
            }
        }
        if encoding_mask & HAS_SERVER_TIMESTAMP != 0 {
            size += self.server_timestamp.as_ref().unwrap().byte_len();
            if encoding_mask & HAS_SERVER_PICOSECONDS != 0 {
                size += self.server_picoseconds.as_ref().unwrap().byte_len();
            }
        }
        size
    }

    fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
        let mut size = 0;

        let encoding_mask = self.encoding_mask();
        size += encoding_mask.encode(stream)?;

        if encoding_mask & HAS_VALUE != 0 {
            size += self.value.as_ref().unwrap().encode(stream)?;
        }
        if encoding_mask & HAS_STATUS != 0 {
            size += self.status.as_ref().unwrap().encode(stream)?;
        }
        if encoding_mask & HAS_SOURCE_TIMESTAMP != 0 {
            size += self.source_timestamp.as_ref().unwrap().encode(stream)?;
            if encoding_mask & HAS_SOURCE_PICOSECONDS != 0 {
                size += self.source_picoseconds.as_ref().unwrap().encode(stream)?;
            }
        }
        if encoding_mask & HAS_SERVER_TIMESTAMP != 0 {
            size += self.server_timestamp.as_ref().unwrap().encode(stream)?;
            if encoding_mask & HAS_SERVER_PICOSECONDS != 0 {
                size += self.server_picoseconds.as_ref().unwrap().encode(stream)?;
            }
        }
        Ok(size)
    }

    fn decode<S: Read>(stream: &mut S) -> EncodingResult<Self> {
        let encoding_mask = Byte::decode(stream)?;

        // Value
        let value = if encoding_mask & HAS_VALUE != 0 {
            Some(Variant::decode(stream)?)
        } else {
            None
        };

        // Status
        let status = if encoding_mask & HAS_STATUS != 0 {
            Some(StatusCode::decode(stream)?)
        } else {
            None
        };

        // Source timestamp
        let source_timestamp = if encoding_mask & HAS_SOURCE_TIMESTAMP != 0 {
            Some(DateTime::decode(stream)?)
        } else {
            None
        };
        let source_picoseconds = if encoding_mask & HAS_SOURCE_PICOSECONDS != 0 {
            Some(Int16::decode(stream)?)
        } else {
            None
        };
        // Server timestamp
        let server_timestamp = if encoding_mask & HAS_SERVER_TIMESTAMP != 0 {
            Some(DateTime::decode(stream)?)
        } else {
            None
        };
        let server_picoseconds = if encoding_mask & HAS_SERVER_PICOSECONDS != 0 {
            Some(Int16::decode(stream)?)
        } else {
            None
        };
        // Pico second values are discarded if associated timestamp is not supplied
        Ok(DataValue {
            value,
            status,
            source_picoseconds: if source_timestamp.is_some() { source_picoseconds } else { None },
            source_timestamp,
            server_picoseconds: if server_timestamp.is_some() { server_picoseconds } else { None },
            server_timestamp,
        })
    }
}

impl DataValue {
    pub fn new<T>(value: T) -> DataValue where T: 'static + Into<Variant> {
        let now = DateTime::now();
        DataValue {
            value: Some(Variant::new(value)),
            status: Some(Good),
            source_timestamp: Some(now.clone()),
            source_picoseconds: Some(0),
            server_timestamp: Some(now.clone()),
            server_picoseconds: Some(0),
        }
    }

    pub fn null() -> DataValue {
        let now = DateTime::now();
        DataValue {
            value: None,
            status: Some(Good),
            source_timestamp: Some(now.clone()),
            source_picoseconds: Some(0),
            server_timestamp: Some(now.clone()),
            server_picoseconds: Some(0),
        }
    }

    fn encoding_mask(&self) -> Byte {
        let mut encoding_mask: Byte = 0;
        if self.value.is_some() {
            encoding_mask |= HAS_VALUE;
        }
        if self.status.is_some() {
            encoding_mask |= HAS_STATUS;
        }
        if self.source_timestamp.is_some() {
            encoding_mask |= HAS_SOURCE_TIMESTAMP;
            if self.source_picoseconds.is_some() {
                encoding_mask |= HAS_SOURCE_PICOSECONDS;
            }
        }
        if self.server_timestamp.is_some() {
            encoding_mask |= HAS_SERVER_TIMESTAMP;
            if self.server_picoseconds.is_some() {
                encoding_mask |= HAS_SERVER_PICOSECONDS;
            }
        }
        encoding_mask
    }
}