opcua_types/variant/
into.rs

1use uuid::Uuid;
2
3use crate::{
4    ByteString, DataValue, DateTime, DateTimeUtc, DiagnosticInfo, DynEncodable, ExpandedNodeId,
5    ExtensionObject, Guid, LocalizedText, NodeId, QualifiedName, StatusCode, UAString,
6};
7
8use super::{Array, Variant, VariantScalarTypeId, VariantType, XmlElement};
9
10/// Trait implemented by types that can be converted to a variant.
11/// This is a workaround for specialization in `EventField`.
12///
13/// Any type that implements this also implements `Into<Variant>` (and variant
14/// implements `From<T> where T : IntoVariant`). Variant also implements
15/// `From<Vec<T>>` and `From<Option<T>>`, so prefer to use that unless you
16/// need to special case `Vec` and `Option` behavior, like `EventField` does.
17pub trait IntoVariant {
18    /// Convert self into a variant.
19    fn into_variant(self) -> Variant;
20}
21
22macro_rules! impl_into_variant {
23    ($tp:ty, $venum:ident) => {
24        impl IntoVariant for $tp {
25            fn into_variant(self) -> Variant {
26                Variant::$venum(self)
27            }
28        }
29    };
30}
31
32macro_rules! impl_into_variant_boxed {
33    ($tp:ty, $venum:ident) => {
34        impl IntoVariant for $tp {
35            fn into_variant(self) -> Variant {
36                Variant::$venum(Box::new(self))
37            }
38        }
39
40        impl IntoVariant for Box<$tp> {
41            fn into_variant(self) -> Variant {
42                Variant::$venum(self)
43            }
44        }
45    };
46}
47
48impl From<()> for Variant {
49    fn from(_: ()) -> Self {
50        Variant::Empty
51    }
52}
53
54impl_into_variant!(bool, Boolean);
55impl_into_variant!(i8, SByte);
56impl_into_variant!(u8, Byte);
57impl_into_variant!(i16, Int16);
58impl_into_variant!(u16, UInt16);
59impl_into_variant!(i32, Int32);
60impl_into_variant!(u32, UInt32);
61impl_into_variant!(i64, Int64);
62impl_into_variant!(u64, UInt64);
63impl_into_variant!(f32, Float);
64impl_into_variant!(f64, Double);
65impl_into_variant!(UAString, String);
66impl_into_variant!(XmlElement, XmlElement);
67impl_into_variant_boxed!(DateTime, DateTime);
68impl_into_variant_boxed!(Guid, Guid);
69impl_into_variant!(StatusCode, StatusCode);
70impl_into_variant!(ByteString, ByteString);
71impl_into_variant_boxed!(QualifiedName, QualifiedName);
72impl_into_variant_boxed!(LocalizedText, LocalizedText);
73impl_into_variant_boxed!(NodeId, NodeId);
74impl_into_variant_boxed!(ExpandedNodeId, ExpandedNodeId);
75impl_into_variant!(ExtensionObject, ExtensionObject);
76impl_into_variant_boxed!(DataValue, DataValue);
77impl_into_variant_boxed!(DiagnosticInfo, DiagnosticInfo);
78impl_into_variant_boxed!(Array, Array);
79
80impl IntoVariant for &str {
81    fn into_variant(self) -> Variant {
82        Variant::String(UAString::from(self))
83    }
84}
85
86impl IntoVariant for String {
87    fn into_variant(self) -> Variant {
88        Variant::String(UAString::from(self))
89    }
90}
91
92impl IntoVariant for Uuid {
93    fn into_variant(self) -> Variant {
94        Variant::Guid(Box::new(self.into()))
95    }
96}
97
98impl IntoVariant for DateTimeUtc {
99    fn into_variant(self) -> Variant {
100        Variant::DateTime(Box::new(self.into()))
101    }
102}
103
104impl<T> IntoVariant for T
105where
106    T: DynEncodable,
107{
108    fn into_variant(self) -> Variant {
109        Variant::ExtensionObject(ExtensionObject::new(self))
110    }
111}
112
113impl<T> From<T> for Variant
114where
115    T: IntoVariant,
116{
117    fn from(value: T) -> Self {
118        value.into_variant()
119    }
120}
121
122impl<T> From<Option<T>> for Variant
123where
124    T: Into<Variant>,
125{
126    fn from(value: Option<T>) -> Self {
127        match value {
128            Some(v) => v.into(),
129            None => Variant::Empty,
130        }
131    }
132}
133
134impl<'a, T> From<&'a Vec<T>> for Variant
135where
136    T: Into<Variant> + VariantType + Clone,
137{
138    fn from(value: &'a Vec<T>) -> Self {
139        Self::from(value.as_slice())
140    }
141}
142
143impl<T> From<Vec<T>> for Variant
144where
145    T: Into<Variant> + VariantType,
146{
147    fn from(value: Vec<T>) -> Self {
148        let array: Vec<Variant> = value.into_iter().map(|v| v.into()).collect();
149        Variant::from((T::variant_type_id(), array))
150    }
151}
152
153impl<'a, T> From<&'a [T]> for Variant
154where
155    T: Into<Variant> + VariantType + Clone,
156{
157    fn from(value: &'a [T]) -> Self {
158        let array: Vec<Variant> = value.iter().map(|v| v.clone().into()).collect();
159        Variant::from((T::variant_type_id(), array))
160    }
161}
162
163impl<'a, 'b> From<(VariantScalarTypeId, &'a [&'b str])> for Variant {
164    fn from(v: (VariantScalarTypeId, &'a [&'b str])) -> Self {
165        let values: Vec<Variant> = v.1.iter().map(|v| Variant::from(*v)).collect();
166        let value = Array::new(v.0, values).unwrap();
167        Variant::from(value)
168    }
169}
170
171impl<T: Into<Variant>> From<(VariantScalarTypeId, Vec<T>)> for Variant {
172    fn from(v: (VariantScalarTypeId, Vec<T>)) -> Self {
173        let value = Array::new(v.0, v.1.into_iter().map(|v| v.into()).collect::<Vec<_>>()).unwrap();
174        Variant::from(value)
175    }
176}
177
178impl<T: Into<Variant>> From<(VariantScalarTypeId, Vec<T>, Vec<u32>)> for Variant {
179    fn from(v: (VariantScalarTypeId, Vec<T>, Vec<u32>)) -> Self {
180        let value = Array::new_multi(
181            v.0,
182            v.1.into_iter().map(|v| v.into()).collect::<Vec<_>>(),
183            v.2,
184        )
185        .unwrap();
186        Variant::from(value)
187    }
188}