opcua_types/variant/
from.rs1use uuid::Uuid;
2
3use crate::{
4 ByteString, DataValue, DateTime, DateTimeUtc, DiagnosticInfo, DynEncodable, Error,
5 ExpandedNodeId, ExtensionObject, Guid, LocalizedText, NodeId, QualifiedName, StatusCode,
6 UAString, VariantScalarTypeId,
7};
8
9use super::{Variant, XmlElement};
10
11pub trait TryFromVariant: Sized {
16 fn try_from_variant(v: Variant) -> Result<Self, Error>;
18}
19
20macro_rules! impl_from_variant_primitive {
21 ($tp:ty, $vt:ident) => {
22 impl TryFromVariant for $tp {
23 fn try_from_variant(v: Variant) -> Result<Self, Error> {
24 let cast = v.cast(VariantScalarTypeId::$vt);
25 if let Variant::$vt(v) = cast {
26 Ok(v)
27 } else {
28 Err(Error::new(
29 StatusCode::BadTypeMismatch,
30 concat!("Unable to convert variant to ", stringify!($vt)),
31 ))
32 }
33 }
34 }
35 };
36}
37
38macro_rules! impl_from_variant_primitive_unbox {
39 ($tp:ty, $vt:ident) => {
40 impl TryFromVariant for $tp {
41 fn try_from_variant(v: Variant) -> Result<Self, Error> {
42 let cast = v.cast(VariantScalarTypeId::$vt);
43 if let Variant::$vt(v) = cast {
44 Ok(*v)
45 } else {
46 Err(Error::new(
47 StatusCode::BadTypeMismatch,
48 concat!("Unable to convert variant to ", stringify!($vt)),
49 ))
50 }
51 }
52 }
53 };
54}
55
56impl_from_variant_primitive!(bool, Boolean);
57impl_from_variant_primitive!(i8, SByte);
58impl_from_variant_primitive!(u8, Byte);
59impl_from_variant_primitive!(i16, Int16);
60impl_from_variant_primitive!(u16, UInt16);
61impl_from_variant_primitive!(i32, Int32);
62impl_from_variant_primitive!(u32, UInt32);
63impl_from_variant_primitive!(i64, Int64);
64impl_from_variant_primitive!(u64, UInt64);
65impl_from_variant_primitive!(f32, Float);
66impl_from_variant_primitive!(f64, Double);
67impl_from_variant_primitive!(UAString, String);
68impl_from_variant_primitive!(XmlElement, XmlElement);
69impl_from_variant_primitive_unbox!(DateTime, DateTime);
70impl_from_variant_primitive_unbox!(Guid, Guid);
71impl_from_variant_primitive!(StatusCode, StatusCode);
72impl_from_variant_primitive!(ByteString, ByteString);
73impl_from_variant_primitive_unbox!(QualifiedName, QualifiedName);
74impl_from_variant_primitive_unbox!(LocalizedText, LocalizedText);
75impl_from_variant_primitive_unbox!(NodeId, NodeId);
76impl_from_variant_primitive_unbox!(ExpandedNodeId, ExpandedNodeId);
77impl_from_variant_primitive!(ExtensionObject, ExtensionObject);
78impl_from_variant_primitive_unbox!(DataValue, DataValue);
79impl_from_variant_primitive_unbox!(DiagnosticInfo, DiagnosticInfo);
80
81impl TryFromVariant for String {
82 fn try_from_variant(v: Variant) -> Result<Self, Error> {
83 Ok(UAString::try_from_variant(v)?.into())
84 }
85}
86
87impl TryFromVariant for Uuid {
88 fn try_from_variant(v: Variant) -> Result<Self, Error> {
89 Ok(Guid::try_from_variant(v)?.into())
90 }
91}
92
93impl TryFromVariant for DateTimeUtc {
94 fn try_from_variant(v: Variant) -> Result<Self, Error> {
95 Ok(DateTime::try_from_variant(v)?.as_chrono())
96 }
97}
98
99impl<T> TryFromVariant for T
100where
101 T: DynEncodable,
102{
103 fn try_from_variant(v: Variant) -> Result<Self, Error> {
104 let Variant::ExtensionObject(o) = v else {
105 return Err(Error::new(
106 StatusCode::BadTypeMismatch,
107 "Variant is not extension object",
108 ));
109 };
110 o.into_inner_as().map(|v| *v).ok_or_else(|| {
111 Error::new(
112 StatusCode::BadTypeMismatch,
113 "Variant is extension object, but not requested type",
114 )
115 })
116 }
117}
118
119impl<T> TryFromVariant for Option<T>
120where
121 T: TryFromVariant,
122{
123 fn try_from_variant(v: Variant) -> Result<Self, Error> {
124 if v.is_empty() {
125 return Ok(None);
126 }
127 Ok(Some(T::try_from_variant(v)?))
128 }
129}
130
131impl<T> TryFromVariant for Vec<T>
132where
133 T: TryFromVariant,
134{
135 fn try_from_variant(v: Variant) -> Result<Self, Error> {
136 match v {
137 Variant::Empty => Err(Error::new(
138 StatusCode::BadTypeMismatch,
139 "Attempted to cast empty variant to array",
140 )),
141 Variant::Array(a) => a
142 .values
143 .into_iter()
144 .map(|v| T::try_from_variant(v))
145 .collect::<Result<Vec<_>, _>>(),
146 r => Ok(vec![T::try_from_variant(r)?]),
147 }
148 }
149}
150
151impl TryFromVariant for Variant {
152 fn try_from_variant(v: Variant) -> Result<Self, Error> {
153 Ok(v)
154 }
155}
156
157impl<const N: usize, T> TryFromVariant for [T; N]
158where
159 T: TryFromVariant,
160{
161 fn try_from_variant(v: Variant) -> Result<Self, Error> {
162 let vals = match v {
163 Variant::Empty => {
164 return Err(Error::new(
165 StatusCode::BadTypeMismatch,
166 "Attempted to cast empty variant to array",
167 ))
168 }
169 Variant::Array(a) => {
170 if N != a.values.len() {
171 return Err(Error::new(
172 StatusCode::BadTypeMismatch,
173 "Array size mismatch",
174 ));
175 }
176 a.values
177 .into_iter()
178 .map(|v| T::try_from_variant(v))
179 .collect::<Result<Vec<_>, _>>()?
180 }
181 r => {
182 if N != 1 {
183 return Err(Error::new(
184 StatusCode::BadTypeMismatch,
185 "Array size mismatch",
186 ));
187 }
188 vec![T::try_from_variant(r)?]
189 }
190 };
191
192 vals.try_into()
193 .map_err(|_| Error::new(StatusCode::BadTypeMismatch, "Array size mismatch"))
194 }
195}