use std::io::{Read, Write};
use crate::types::{
byte_string::ByteString, date_time::*, encoding::*, guid::Guid, localized_text::LocalizedText,
node_id::NodeId, qualified_name::QualifiedName, service_types::TimestampsToReturn,
status_codes::StatusCode, string::UAString, variant::Variant,
};
bitflags! {
struct DataValueFlags: u8 {
const HAS_VALUE = 0x1;
const HAS_STATUS = 0x2;
const HAS_SOURCE_TIMESTAMP = 0x4;
const HAS_SERVER_TIMESTAMP = 0x8;
const HAS_SOURCE_PICOSECONDS = 0x10;
const HAS_SERVER_PICOSECONDS = 0x20;
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct DataValue {
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<Variant>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<StatusCode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_timestamp: Option<DateTime>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_picoseconds: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub server_timestamp: Option<DateTime>,
#[serde(skip_serializing_if = "Option::is_none")]
pub server_picoseconds: Option<u16>,
}
impl BinaryEncoder<DataValue> for DataValue {
fn byte_len(&self) -> usize {
let mut size = 1;
let encoding_mask = self.encoding_mask();
if encoding_mask.contains(DataValueFlags::HAS_VALUE) {
size += self.value.as_ref().unwrap().byte_len();
}
if encoding_mask.contains(DataValueFlags::HAS_STATUS) {
size += self.status.as_ref().unwrap().byte_len();
}
if encoding_mask.contains(DataValueFlags::HAS_SOURCE_TIMESTAMP) {
size += self.source_timestamp.as_ref().unwrap().byte_len();
if encoding_mask.contains(DataValueFlags::HAS_SOURCE_PICOSECONDS) {
size += self.source_picoseconds.as_ref().unwrap().byte_len();
}
}
if encoding_mask.contains(DataValueFlags::HAS_SERVER_TIMESTAMP) {
size += self.server_timestamp.as_ref().unwrap().byte_len();
if encoding_mask.contains(DataValueFlags::HAS_SERVER_PICOSECONDS) {
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.bits().encode(stream)?;
if encoding_mask.contains(DataValueFlags::HAS_VALUE) {
size += self.value.as_ref().unwrap().encode(stream)?;
}
if encoding_mask.contains(DataValueFlags::HAS_STATUS) {
size += self.status.as_ref().unwrap().bits().encode(stream)?;
}
if encoding_mask.contains(DataValueFlags::HAS_SOURCE_TIMESTAMP) {
size += self.source_timestamp.as_ref().unwrap().encode(stream)?;
if encoding_mask.contains(DataValueFlags::HAS_SOURCE_PICOSECONDS) {
size += self.source_picoseconds.as_ref().unwrap().encode(stream)?;
}
}
if encoding_mask.contains(DataValueFlags::HAS_SERVER_TIMESTAMP) {
size += self.server_timestamp.as_ref().unwrap().encode(stream)?;
if encoding_mask.contains(DataValueFlags::HAS_SERVER_PICOSECONDS) {
size += self.server_picoseconds.as_ref().unwrap().encode(stream)?;
}
}
Ok(size)
}
fn decode<S: Read>(stream: &mut S, decoding_options: &DecodingOptions) -> EncodingResult<Self> {
let encoding_mask =
DataValueFlags::from_bits_truncate(u8::decode(stream, decoding_options)?);
let value = if encoding_mask.contains(DataValueFlags::HAS_VALUE) {
Some(Variant::decode(stream, decoding_options)?)
} else {
None
};
let status = if encoding_mask.contains(DataValueFlags::HAS_STATUS) {
let status = StatusCode::from_bits_truncate(u32::decode(stream, decoding_options)?);
Some(status)
} else {
None
};
let source_timestamp = if encoding_mask.contains(DataValueFlags::HAS_SOURCE_TIMESTAMP) {
let decoding_options = DecodingOptions {
client_offset: chrono::Duration::zero(),
..decoding_options.clone()
};
Some(DateTime::decode(stream, &decoding_options)?)
} else {
None
};
let source_picoseconds = if encoding_mask.contains(DataValueFlags::HAS_SOURCE_PICOSECONDS) {
Some(u16::decode(stream, decoding_options)?)
} else {
None
};
let server_timestamp = if encoding_mask.contains(DataValueFlags::HAS_SERVER_TIMESTAMP) {
Some(DateTime::decode(stream, decoding_options)?)
} else {
None
};
let server_picoseconds = if encoding_mask.contains(DataValueFlags::HAS_SERVER_PICOSECONDS) {
Some(u16::decode(stream, decoding_options)?)
} else {
None
};
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 From<bool> for DataValue {
fn from(v: bool) -> Self {
Self::from(Variant::from(v))
}
}
impl From<u8> for DataValue {
fn from(v: u8) -> Self {
Self::from(Variant::from(v))
}
}
impl From<i8> for DataValue {
fn from(v: i8) -> Self {
Self::from(Variant::from(v))
}
}
impl From<i16> for DataValue {
fn from(v: i16) -> Self {
Self::from(Variant::from(v))
}
}
impl From<u16> for DataValue {
fn from(v: u16) -> Self {
Self::from(Variant::from(v))
}
}
impl From<i32> for DataValue {
fn from(v: i32) -> Self {
Self::from(Variant::from(v))
}
}
impl From<u32> for DataValue {
fn from(v: u32) -> Self {
Self::from(Variant::from(v))
}
}
impl From<i64> for DataValue {
fn from(v: i64) -> Self {
Self::from(Variant::from(v))
}
}
impl From<u64> for DataValue {
fn from(v: u64) -> Self {
Self::from(Variant::from(v))
}
}
impl From<f32> for DataValue {
fn from(v: f32) -> Self {
Self::from(Variant::from(v))
}
}
impl From<f64> for DataValue {
fn from(v: f64) -> Self {
Self::from(Variant::from(v))
}
}
impl<'a> From<&'a str> for DataValue {
fn from(v: &'a str) -> Self {
Self::from(Variant::from(v))
}
}
impl From<String> for DataValue {
fn from(v: String) -> Self {
Self::from(Variant::from(v))
}
}
impl From<UAString> for DataValue {
fn from(v: UAString) -> Self {
Self::from(Variant::from(v))
}
}
impl From<DateTime> for DataValue {
fn from(v: DateTime) -> Self {
Self::from(Variant::from(v))
}
}
impl From<Guid> for DataValue {
fn from(v: Guid) -> Self {
Self::from(Variant::from(v))
}
}
impl From<StatusCode> for DataValue {
fn from(v: StatusCode) -> Self {
Self::from(Variant::from(v))
}
}
impl From<ByteString> for DataValue {
fn from(v: ByteString) -> Self {
Self::from(Variant::from(v))
}
}
impl From<QualifiedName> for DataValue {
fn from(v: QualifiedName) -> Self {
Self::from(Variant::from(v))
}
}
impl From<LocalizedText> for DataValue {
fn from(v: LocalizedText) -> Self {
Self::from(Variant::from(v))
}
}
impl From<NodeId> for DataValue {
fn from(v: NodeId) -> Self {
Self::from(Variant::from(v))
}
}
impl From<Variant> for DataValue {
fn from(v: Variant) -> Self {
DataValue::value_only(v)
}
}
impl From<(Variant, StatusCode)> for DataValue {
fn from(v: (Variant, StatusCode)) -> Self {
DataValue {
value: Some(v.0),
status: Some(v.1),
source_timestamp: None,
source_picoseconds: None,
server_timestamp: None,
server_picoseconds: None,
}
}
}
impl Default for DataValue {
fn default() -> Self {
Self::null()
}
}
impl DataValue {
pub fn value_only<V>(value: V) -> DataValue
where
V: Into<Variant>,
{
DataValue {
value: Some(value.into()),
status: None,
source_timestamp: None,
source_picoseconds: None,
server_timestamp: None,
server_picoseconds: None,
}
}
pub fn new_now<V>(value: V) -> DataValue
where
V: Into<Variant>,
{
let now = DateTime::now();
DataValue {
value: Some(value.into()),
status: Some(StatusCode::Good),
source_timestamp: Some(now),
source_picoseconds: Some(0),
server_timestamp: Some(now),
server_picoseconds: Some(0),
}
}
pub fn null() -> DataValue {
DataValue {
value: None,
status: None,
source_timestamp: None,
source_picoseconds: None,
server_timestamp: None,
server_picoseconds: None,
}
}
pub fn set_value<V>(
&mut self,
value: V,
source_timestamp: &DateTime,
server_timestamp: &DateTime,
) where
V: Into<Variant>,
{
self.value = Some(value.into());
self.source_timestamp = Some(*source_timestamp);
self.source_picoseconds = Some(0);
self.server_timestamp = Some(*server_timestamp);
self.server_picoseconds = Some(0);
}
pub fn set_timestamps(
&mut self,
timestamps_to_return: TimestampsToReturn,
source_timestamp: DateTime,
server_timestamp: DateTime,
) {
match timestamps_to_return {
TimestampsToReturn::Source => {
self.source_timestamp = Some(source_timestamp);
self.source_picoseconds = Some(0);
self.server_timestamp = None;
self.server_picoseconds = None;
}
TimestampsToReturn::Server => {
self.source_timestamp = None;
self.source_picoseconds = None;
self.server_timestamp = Some(server_timestamp);
self.server_picoseconds = Some(0);
}
TimestampsToReturn::Both => {
self.source_timestamp = Some(source_timestamp);
self.source_picoseconds = Some(0);
self.server_timestamp = Some(server_timestamp);
self.server_picoseconds = Some(0);
}
TimestampsToReturn::Neither => {
self.source_timestamp = None;
self.source_picoseconds = None;
self.server_timestamp = None;
self.server_picoseconds = None;
}
_ => {}
}
}
pub fn status(&self) -> StatusCode {
self.status.map_or(StatusCode::Good, |s| s)
}
pub fn is_valid(&self) -> bool {
self.status().status().is_good()
}
fn encoding_mask(&self) -> DataValueFlags {
let mut encoding_mask = DataValueFlags::empty();
if self.value.is_some() {
encoding_mask |= DataValueFlags::HAS_VALUE;
}
if self.status.is_some() {
encoding_mask |= DataValueFlags::HAS_STATUS;
}
if self.source_timestamp.is_some() {
encoding_mask |= DataValueFlags::HAS_SOURCE_TIMESTAMP;
if self.source_picoseconds.is_some() {
encoding_mask |= DataValueFlags::HAS_SOURCE_PICOSECONDS;
}
}
if self.server_timestamp.is_some() {
encoding_mask |= DataValueFlags::HAS_SERVER_TIMESTAMP;
if self.server_picoseconds.is_some() {
encoding_mask |= DataValueFlags::HAS_SERVER_PICOSECONDS;
}
}
encoding_mask
}
}