1use std::io::{Read, Write};
8
9use crate::{
10 byte_string::ByteString, date_time::*, guid::Guid, localized_text::LocalizedText,
11 node_id::NodeId, qualified_name::QualifiedName, status_code::StatusCode, string::UAString,
12 variant::Variant, BinaryDecodable, BinaryEncodable, Context, EncodingResult,
13 TimestampsToReturn,
14};
15use bitflags::bitflags;
16
17bitflags! {
18 struct DataValueFlags: u8 {
19 const HAS_VALUE = 0x1;
21 const HAS_STATUS = 0x2;
23 const HAS_SOURCE_TIMESTAMP = 0x4;
25 const HAS_SERVER_TIMESTAMP = 0x8;
27 const HAS_SOURCE_PICOSECONDS = 0x10;
29 const HAS_SERVER_PICOSECONDS = 0x20;
31 }
32}
33
34#[allow(unused)]
35mod opcua {
36 pub(super) use crate as types;
37}
38
39#[derive(Debug, Clone, PartialEq, crate::UaNullable)]
42#[cfg_attr(
43 feature = "json",
44 derive(opcua_macros::JsonEncodable, opcua_macros::JsonDecodable)
45)]
46pub struct DataValue {
47 pub value: Option<Variant>,
50 pub status: Option<StatusCode>,
53 pub source_timestamp: Option<DateTime>,
56 pub source_picoseconds: Option<u16>,
60 pub server_timestamp: Option<DateTime>,
63 pub server_picoseconds: Option<u16>,
67}
68
69#[cfg(feature = "xml")]
73mod xml {
74 use super::DataValue;
75
76 impl crate::xml::XmlEncodable for DataValue {
77 fn encode(
78 &self,
79 stream: &mut crate::xml::XmlStreamWriter<&mut dyn std::io::Write>,
80 ctx: &crate::Context<'_>,
81 ) -> crate::EncodingResult<()> {
82 use crate::xml::XmlWriteExt;
83 stream.encode_child("Value", &self.value, ctx)?;
84 stream.encode_child("StatusCode", &self.status, ctx)?;
85 stream.encode_child("SourceTimestamp", &self.source_timestamp, ctx)?;
86 stream.encode_child("SourcePicoseconds", &self.source_picoseconds, ctx)?;
87 stream.encode_child("ServerTimestamp", &self.server_timestamp, ctx)?;
88 stream.encode_child("ServerPicoseconds", &self.server_picoseconds, ctx)?;
89 Ok(())
90 }
91 }
92 impl crate::xml::XmlDecodable for DataValue {
93 fn decode(
94 stream: &mut crate::xml::XmlStreamReader<&mut dyn std::io::Read>,
95 ctx: &crate::Context<'_>,
96 ) -> crate::EncodingResult<Self> {
97 use crate::xml::XmlReadExt;
98 let mut value = None;
99 let mut status = None;
100 let mut source_timestamp = None;
101 let mut source_picoseconds = None;
102 let mut server_timestamp = None;
103 let mut server_picoseconds = None;
104 stream.iter_children(
105 |__key, stream, ctx| {
106 match __key.as_str() {
107 "Value" => {
108 value = Some(crate::xml::XmlDecodable::decode(stream, ctx)?);
109 }
110 "StatusCode" => {
111 status = Some(crate::xml::XmlDecodable::decode(stream, ctx)?);
112 }
113 "SourceTimestamp" => {
114 source_timestamp = Some(crate::xml::XmlDecodable::decode(stream, ctx)?);
115 }
116 "SourcePicoseconds" => {
117 source_picoseconds =
118 Some(crate::xml::XmlDecodable::decode(stream, ctx)?);
119 }
120 "ServerTimestamp" => {
121 server_timestamp = Some(crate::xml::XmlDecodable::decode(stream, ctx)?);
122 }
123 "ServerPicoseconds" => {
124 server_picoseconds =
125 Some(crate::xml::XmlDecodable::decode(stream, ctx)?);
126 }
127 _ => {
128 stream.skip_value()?;
129 }
130 }
131 Ok(())
132 },
133 ctx,
134 )?;
135 Ok(Self {
136 value: value.unwrap_or_default(),
137 status: status.unwrap_or_default(),
138 source_timestamp: source_timestamp.unwrap_or_default(),
139 source_picoseconds: source_picoseconds.unwrap_or_default(),
140 server_timestamp: server_timestamp.unwrap_or_default(),
141 server_picoseconds: server_picoseconds.unwrap_or_default(),
142 })
143 }
144 }
145 impl crate::xml::XmlType for DataValue {
146 const TAG: &'static str = "DataValue";
147 }
148}
149
150impl BinaryEncodable for DataValue {
151 fn byte_len(&self, ctx: &opcua::types::Context<'_>) -> usize {
152 let mut size = 1;
153 let encoding_mask = self.encoding_mask();
154 if encoding_mask.contains(DataValueFlags::HAS_VALUE) {
155 size += self.value.as_ref().unwrap().byte_len(ctx);
156 }
157 if encoding_mask.contains(DataValueFlags::HAS_STATUS) {
158 size += self.status.as_ref().unwrap().byte_len(ctx);
159 }
160 if encoding_mask.contains(DataValueFlags::HAS_SOURCE_TIMESTAMP) {
161 size += self.source_timestamp.as_ref().unwrap().byte_len(ctx);
162 if encoding_mask.contains(DataValueFlags::HAS_SOURCE_PICOSECONDS) {
163 size += self.source_picoseconds.as_ref().unwrap().byte_len(ctx);
164 }
165 }
166 if encoding_mask.contains(DataValueFlags::HAS_SERVER_TIMESTAMP) {
167 size += self.server_timestamp.as_ref().unwrap().byte_len(ctx);
168 if encoding_mask.contains(DataValueFlags::HAS_SERVER_PICOSECONDS) {
169 size += self.server_picoseconds.as_ref().unwrap().byte_len(ctx);
170 }
171 }
172 size
173 }
174
175 fn encode<S: Write + ?Sized>(&self, stream: &mut S, ctx: &Context<'_>) -> EncodingResult<()> {
176 let encoding_mask = self.encoding_mask();
177 encoding_mask.bits().encode(stream, ctx)?;
178
179 if encoding_mask.contains(DataValueFlags::HAS_VALUE) {
180 self.value.as_ref().unwrap().encode(stream, ctx)?;
181 }
182 if encoding_mask.contains(DataValueFlags::HAS_STATUS) {
183 self.status.as_ref().unwrap().bits().encode(stream, ctx)?;
184 }
185 if encoding_mask.contains(DataValueFlags::HAS_SOURCE_TIMESTAMP) {
186 self.source_timestamp
187 .as_ref()
188 .unwrap()
189 .encode(stream, ctx)?;
190 if encoding_mask.contains(DataValueFlags::HAS_SOURCE_PICOSECONDS) {
191 self.source_picoseconds
192 .as_ref()
193 .unwrap()
194 .encode(stream, ctx)?;
195 }
196 }
197 if encoding_mask.contains(DataValueFlags::HAS_SERVER_TIMESTAMP) {
198 self.server_timestamp
199 .as_ref()
200 .unwrap()
201 .encode(stream, ctx)?;
202 if encoding_mask.contains(DataValueFlags::HAS_SERVER_PICOSECONDS) {
203 self.server_picoseconds
204 .as_ref()
205 .unwrap()
206 .encode(stream, ctx)?;
207 }
208 }
209 Ok(())
210 }
211}
212
213impl BinaryDecodable for DataValue {
214 fn decode<S: Read + ?Sized>(stream: &mut S, ctx: &Context<'_>) -> EncodingResult<Self> {
215 let encoding_mask = DataValueFlags::from_bits_truncate(u8::decode(stream, ctx)?);
216
217 let value = if encoding_mask.contains(DataValueFlags::HAS_VALUE) {
219 Some(Variant::decode(stream, ctx)?)
220 } else {
221 None
222 };
223 let status = if encoding_mask.contains(DataValueFlags::HAS_STATUS) {
225 let status = StatusCode::from(u32::decode(stream, ctx)?);
226 Some(status)
227 } else {
228 None
229 };
230 let source_timestamp = if encoding_mask.contains(DataValueFlags::HAS_SOURCE_TIMESTAMP) {
232 let ctx = ctx.with_zero_offset();
235 Some(DateTime::decode(stream, &ctx)?)
236 } else {
237 None
238 };
239 let source_picoseconds = if encoding_mask.contains(DataValueFlags::HAS_SOURCE_PICOSECONDS) {
240 Some(u16::decode(stream, ctx)?)
241 } else {
242 None
243 };
244 let server_timestamp = if encoding_mask.contains(DataValueFlags::HAS_SERVER_TIMESTAMP) {
246 Some(DateTime::decode(stream, ctx)?)
247 } else {
248 None
249 };
250 let server_picoseconds = if encoding_mask.contains(DataValueFlags::HAS_SERVER_PICOSECONDS) {
251 Some(u16::decode(stream, ctx)?)
252 } else {
253 None
254 };
255 Ok(DataValue {
257 value,
258 status,
259 source_picoseconds: if source_timestamp.is_some() {
260 source_picoseconds
261 } else {
262 None
263 },
264 source_timestamp,
265 server_picoseconds: if server_timestamp.is_some() {
266 server_picoseconds
267 } else {
268 None
269 },
270 server_timestamp,
271 })
272 }
273}
274
275impl From<bool> for DataValue {
279 fn from(v: bool) -> Self {
280 Self::from(Variant::from(v))
281 }
282}
283
284impl From<u8> for DataValue {
285 fn from(v: u8) -> Self {
286 Self::from(Variant::from(v))
287 }
288}
289
290impl From<i8> for DataValue {
291 fn from(v: i8) -> Self {
292 Self::from(Variant::from(v))
293 }
294}
295
296impl From<i16> for DataValue {
297 fn from(v: i16) -> Self {
298 Self::from(Variant::from(v))
299 }
300}
301
302impl From<u16> for DataValue {
303 fn from(v: u16) -> Self {
304 Self::from(Variant::from(v))
305 }
306}
307
308impl From<i32> for DataValue {
309 fn from(v: i32) -> Self {
310 Self::from(Variant::from(v))
311 }
312}
313
314impl From<u32> for DataValue {
315 fn from(v: u32) -> Self {
316 Self::from(Variant::from(v))
317 }
318}
319
320impl From<i64> for DataValue {
321 fn from(v: i64) -> Self {
322 Self::from(Variant::from(v))
323 }
324}
325
326impl From<u64> for DataValue {
327 fn from(v: u64) -> Self {
328 Self::from(Variant::from(v))
329 }
330}
331
332impl From<f32> for DataValue {
333 fn from(v: f32) -> Self {
334 Self::from(Variant::from(v))
335 }
336}
337
338impl From<f64> for DataValue {
339 fn from(v: f64) -> Self {
340 Self::from(Variant::from(v))
341 }
342}
343
344impl<'a> From<&'a str> for DataValue {
345 fn from(v: &'a str) -> Self {
346 Self::from(Variant::from(v))
347 }
348}
349
350impl From<String> for DataValue {
351 fn from(v: String) -> Self {
352 Self::from(Variant::from(v))
353 }
354}
355
356impl From<UAString> for DataValue {
357 fn from(v: UAString) -> Self {
358 Self::from(Variant::from(v))
359 }
360}
361
362impl From<DateTime> for DataValue {
363 fn from(v: DateTime) -> Self {
364 Self::from(Variant::from(v))
365 }
366}
367
368impl From<Guid> for DataValue {
369 fn from(v: Guid) -> Self {
370 Self::from(Variant::from(v))
371 }
372}
373
374impl From<StatusCode> for DataValue {
375 fn from(v: StatusCode) -> Self {
376 Self::from(Variant::from(v))
377 }
378}
379
380impl From<ByteString> for DataValue {
381 fn from(v: ByteString) -> Self {
382 Self::from(Variant::from(v))
383 }
384}
385
386impl From<QualifiedName> for DataValue {
387 fn from(v: QualifiedName) -> Self {
388 Self::from(Variant::from(v))
389 }
390}
391
392impl From<LocalizedText> for DataValue {
393 fn from(v: LocalizedText) -> Self {
394 Self::from(Variant::from(v))
395 }
396}
397
398impl From<NodeId> for DataValue {
399 fn from(v: NodeId) -> Self {
400 Self::from(Variant::from(v))
401 }
402}
403impl From<Variant> for DataValue {
406 fn from(v: Variant) -> Self {
407 DataValue::value_only(v)
408 }
409}
410
411impl From<(Variant, StatusCode)> for DataValue {
412 fn from(v: (Variant, StatusCode)) -> Self {
413 DataValue {
414 value: Some(v.0),
415 status: Some(v.1),
416 source_timestamp: None,
417 source_picoseconds: None,
418 server_timestamp: None,
419 server_picoseconds: None,
420 }
421 }
422}
423
424impl Default for DataValue {
454 fn default() -> Self {
455 Self::null()
456 }
457}
458
459impl DataValue {
460 pub fn value_only<V>(value: V) -> DataValue
462 where
463 V: Into<Variant>,
464 {
465 DataValue {
466 value: Some(value.into()),
467 status: None,
468 source_timestamp: None,
469 source_picoseconds: None,
470 server_timestamp: None,
471 server_picoseconds: None,
472 }
473 }
474
475 pub fn new_now<V>(value: V) -> DataValue
483 where
484 V: Into<Variant>,
485 {
486 let now = DateTime::now();
487 DataValue {
488 value: Some(value.into()),
489 status: Some(StatusCode::Good),
490 source_timestamp: Some(now),
491 source_picoseconds: Some(0),
492 server_timestamp: Some(now),
493 server_picoseconds: Some(0),
494 }
495 }
496
497 pub fn new_at<V>(value: V, time: DateTime) -> DataValue
505 where
506 V: Into<Variant>,
507 {
508 DataValue {
509 value: Some(value.into()),
510 status: Some(StatusCode::Good),
511 source_timestamp: Some(time),
512 source_picoseconds: Some(0),
513 server_timestamp: Some(time),
514 server_picoseconds: Some(0),
515 }
516 }
517
518 pub fn new_now_status<V>(value: V, status: StatusCode) -> DataValue
526 where
527 V: Into<Variant>,
528 {
529 let now = DateTime::now();
530 DataValue {
531 value: Some(value.into()),
532 status: Some(status),
533 source_timestamp: Some(now),
534 source_picoseconds: Some(0),
535 server_timestamp: Some(now),
536 server_picoseconds: Some(0),
537 }
538 }
539
540 pub fn new_at_status<V>(value: V, time: DateTime, status: StatusCode) -> DataValue
548 where
549 V: Into<Variant>,
550 {
551 DataValue {
552 value: Some(value.into()),
553 status: Some(status),
554 source_timestamp: Some(time),
555 source_picoseconds: Some(0),
556 server_timestamp: Some(time),
557 server_picoseconds: Some(0),
558 }
559 }
560
561 pub fn null() -> DataValue {
563 DataValue {
564 value: None,
565 status: None,
566 source_timestamp: None,
567 source_picoseconds: None,
568 server_timestamp: None,
569 server_picoseconds: None,
570 }
571 }
572
573 pub fn set_value<V>(
575 &mut self,
576 value: V,
577 source_timestamp: &DateTime,
578 server_timestamp: &DateTime,
579 ) where
580 V: Into<Variant>,
581 {
582 self.value = Some(value.into());
583 self.source_timestamp = Some(*source_timestamp);
584 self.source_picoseconds = Some(0);
585 self.server_timestamp = Some(*server_timestamp);
586 self.server_picoseconds = Some(0);
587 }
588
589 pub fn set_timestamps(
591 &mut self,
592 timestamps_to_return: TimestampsToReturn,
593 source_timestamp: DateTime,
594 server_timestamp: DateTime,
595 ) {
596 match timestamps_to_return {
597 TimestampsToReturn::Source => {
598 self.source_timestamp = Some(source_timestamp);
599 self.source_picoseconds = Some(0);
600 self.server_timestamp = None;
601 self.server_picoseconds = None;
602 }
603 TimestampsToReturn::Server => {
604 self.source_timestamp = None;
605 self.source_picoseconds = None;
606 self.server_timestamp = Some(server_timestamp);
607 self.server_picoseconds = Some(0);
608 }
609 TimestampsToReturn::Both => {
610 self.source_timestamp = Some(source_timestamp);
611 self.source_picoseconds = Some(0);
612 self.server_timestamp = Some(server_timestamp);
613 self.server_picoseconds = Some(0);
614 }
615 TimestampsToReturn::Neither => {
616 self.source_timestamp = None;
617 self.source_picoseconds = None;
618 self.server_timestamp = None;
619 self.server_picoseconds = None;
620 }
621 _ => {}
622 }
623 }
624
625 pub fn status(&self) -> StatusCode {
627 self.status.map_or(StatusCode::Good, |s| s)
628 }
629
630 pub fn is_valid(&self) -> bool {
633 self.status().is_good()
634 }
635
636 fn encoding_mask(&self) -> DataValueFlags {
637 let mut encoding_mask = DataValueFlags::empty();
638 if self.value.is_some() {
639 encoding_mask |= DataValueFlags::HAS_VALUE;
640 }
641 if self.status.is_some() {
642 encoding_mask |= DataValueFlags::HAS_STATUS;
643 }
644 if self.source_timestamp.is_some() {
645 encoding_mask |= DataValueFlags::HAS_SOURCE_TIMESTAMP;
646 if self.source_picoseconds.is_some() {
647 encoding_mask |= DataValueFlags::HAS_SOURCE_PICOSECONDS;
648 }
649 }
650 if self.server_timestamp.is_some() {
651 encoding_mask |= DataValueFlags::HAS_SERVER_TIMESTAMP;
652 if self.server_picoseconds.is_some() {
653 encoding_mask |= DataValueFlags::HAS_SERVER_PICOSECONDS;
654 }
655 }
656 encoding_mask
657 }
658}