1use std::{collections::HashMap, sync::Arc};
2
3use crate::{
4 DataTypeDefinition, EnumField, Error, NodeId, StatusCode, StructureField, StructureType,
5 Variant, VariantScalarTypeId, VariantTypeId,
6};
7
8#[derive(Debug)]
9pub struct EnumTypeInfo {
11 pub variants: HashMap<i64, EnumField>,
13}
14
15#[derive(Debug)]
16pub struct ParsedStructureField {
18 pub name: String,
20 pub type_id: NodeId,
22 pub value_rank: i32,
24 pub array_dimensions: Option<Vec<u32>>,
26 pub is_optional: bool,
28 pub scalar_type: VariantScalarTypeId,
30}
31
32impl ParsedStructureField {
33 pub fn from_field(f: StructureField, scalar_type: VariantScalarTypeId) -> Result<Self, String> {
35 if f.name.is_empty() || f.name.is_null() {
36 return Err("Field has null name".to_owned());
37 }
38 Ok(Self {
39 name: f.name.as_ref().to_owned(),
40 type_id: f.data_type,
41 value_rank: f.value_rank,
42 array_dimensions: f.array_dimensions,
43 is_optional: f.is_optional,
44 scalar_type,
45 })
46 }
47
48 pub fn validate(&self, value: &Variant) -> Result<(), Error> {
50 let ty = match value.type_id() {
51 VariantTypeId::Empty => {
52 if !self.is_optional {
53 return Err(Error::new(
54 StatusCode::BadInvalidArgument,
55 format!("Got null value for non-nullable field {}", self.name),
56 ));
57 } else {
58 return Ok(());
59 }
60 }
61 VariantTypeId::Scalar(ty) => ty,
62 VariantTypeId::Array(ty, dims) => {
63 let rank = dims.map(|d| d.len()).unwrap_or(1);
64 if rank as i32 != self.value_rank {
65 return Err(Error::new(
66 StatusCode::BadInvalidArgument,
67 format!("Invalid dimensions, array dimensions {:?} length must match field value rank {}",
68 dims, self.value_rank)));
69 }
70 ty
71 }
72 };
73 if ty != self.scalar_type {
74 return Err(Error::new(
75 StatusCode::BadInvalidArgument,
76 format!(
77 "Invalid type for field {}. Got {}, expected {}",
78 self.name, ty, self.scalar_type
79 ),
80 ));
81 }
82 Ok(())
83 }
84}
85
86#[derive(Debug)]
87pub struct StructTypeInfo {
89 pub structure_type: StructureType,
91 pub fields: Vec<ParsedStructureField>,
93 pub index_by_name: HashMap<String, usize>,
95 pub encoding_ids: EncodingIds,
97 pub is_abstract: bool,
99 pub node_id: NodeId,
101 pub name: String,
103}
104
105impl StructTypeInfo {
106 pub fn get_field(&self, idx: usize) -> Option<&ParsedStructureField> {
108 self.fields.get(idx)
109 }
110
111 pub fn get_field_by_name(&self, idx: &str) -> Option<&ParsedStructureField> {
113 self.index_by_name
114 .get(idx)
115 .and_then(|i| self.fields.get(*i))
116 }
117
118 pub fn is_supported(&self) -> bool {
123 !matches!(
124 self.structure_type,
125 StructureType::StructureWithSubtypedValues | StructureType::UnionWithSubtypedValues
126 )
127 }
128}
129
130#[derive(Debug, Default)]
131pub struct EncodingIds {
133 pub binary_id: NodeId,
135 pub json_id: NodeId,
137 pub xml_id: NodeId,
139}
140
141#[derive(Debug)]
142pub struct GenericTypeInfo {
143 pub is_abstract: bool,
144}
145
146impl GenericTypeInfo {
147 pub fn new(is_abstract: bool) -> Self {
148 Self { is_abstract }
149 }
150}
151
152#[derive(Debug)]
153pub enum TypeInfo {
155 Enum(Arc<EnumTypeInfo>),
157 Struct(Arc<StructTypeInfo>),
159 Primitive(Arc<GenericTypeInfo>),
161}
162
163#[derive(Debug)]
164pub enum TypeInfoRef<'a> {
166 Enum(&'a Arc<EnumTypeInfo>),
168 Struct(&'a Arc<StructTypeInfo>),
170 Primitive(&'a Arc<GenericTypeInfo>),
172}
173
174impl From<StructTypeInfo> for TypeInfo {
175 fn from(value: StructTypeInfo) -> Self {
176 Self::Struct(Arc::new(value))
177 }
178}
179
180impl From<EnumTypeInfo> for TypeInfo {
181 fn from(value: EnumTypeInfo) -> Self {
182 Self::Enum(Arc::new(value))
183 }
184}
185
186impl From<GenericTypeInfo> for TypeInfo {
187 fn from(value: GenericTypeInfo) -> Self {
188 Self::Primitive(Arc::new(value))
189 }
190}
191
192#[derive(Debug)]
193pub struct ParentIds {
195 parent_ids: HashMap<NodeId, NodeId>,
196}
197
198impl Default for ParentIds {
199 fn default() -> Self {
200 Self::new()
201 }
202}
203
204pub enum DataTypeVariant {
206 Enumeration,
208 Structure,
210 Primitive,
212}
213
214impl ParentIds {
215 pub fn new() -> Self {
217 Self {
218 parent_ids: HashMap::new(),
219 }
220 }
221
222 pub fn add_type(&mut self, node_id: NodeId, parent_id: NodeId) {
224 self.parent_ids.insert(node_id, parent_id);
225 }
226
227 pub fn get_data_type_variant(&self, id: &NodeId) -> Option<DataTypeVariant> {
230 if let Ok(t) = id.as_data_type_id() {
231 match t {
232 crate::DataTypeId::Boolean
233 | crate::DataTypeId::SByte
234 | crate::DataTypeId::Byte
235 | crate::DataTypeId::Int16
236 | crate::DataTypeId::UInt16
237 | crate::DataTypeId::Int32
238 | crate::DataTypeId::UInt32
239 | crate::DataTypeId::Int64
240 | crate::DataTypeId::UInt64
241 | crate::DataTypeId::Float
242 | crate::DataTypeId::Double
243 | crate::DataTypeId::String
244 | crate::DataTypeId::DateTime
245 | crate::DataTypeId::Guid
246 | crate::DataTypeId::ByteString
247 | crate::DataTypeId::XmlElement
248 | crate::DataTypeId::NodeId
249 | crate::DataTypeId::ExpandedNodeId
250 | crate::DataTypeId::StatusCode
251 | crate::DataTypeId::QualifiedName
252 | crate::DataTypeId::LocalizedText
253 | crate::DataTypeId::DataValue
254 | crate::DataTypeId::DiagnosticInfo
255 | crate::DataTypeId::BaseDataType => return Some(DataTypeVariant::Primitive),
256 crate::DataTypeId::Structure | crate::DataTypeId::Decimal => {
257 return Some(DataTypeVariant::Structure)
258 }
259 crate::DataTypeId::Enumeration => return Some(DataTypeVariant::Enumeration),
260 _ => (),
261 }
262 }
263
264 let parent = self.parent_ids.get(id)?;
265 self.get_data_type_variant(parent)
266 }
267
268 pub fn get_builtin_type(&self, id: &NodeId) -> Option<VariantScalarTypeId> {
271 if let Ok(t) = id.as_data_type_id() {
272 match t {
273 crate::DataTypeId::Boolean => return Some(VariantScalarTypeId::Boolean),
274 crate::DataTypeId::SByte => return Some(VariantScalarTypeId::SByte),
275 crate::DataTypeId::Byte => return Some(VariantScalarTypeId::Byte),
276 crate::DataTypeId::Int16 => return Some(VariantScalarTypeId::Int16),
277 crate::DataTypeId::UInt16 => return Some(VariantScalarTypeId::UInt16),
278 crate::DataTypeId::Int32 => return Some(VariantScalarTypeId::Int32),
279 crate::DataTypeId::UInt32 => return Some(VariantScalarTypeId::UInt32),
280 crate::DataTypeId::Int64 => return Some(VariantScalarTypeId::Int64),
281 crate::DataTypeId::UInt64 => return Some(VariantScalarTypeId::UInt64),
282 crate::DataTypeId::Float => return Some(VariantScalarTypeId::Float),
283 crate::DataTypeId::Double => return Some(VariantScalarTypeId::Double),
284 crate::DataTypeId::String => return Some(VariantScalarTypeId::String),
285 crate::DataTypeId::DateTime => return Some(VariantScalarTypeId::DateTime),
286 crate::DataTypeId::Guid => return Some(VariantScalarTypeId::Guid),
287 crate::DataTypeId::ByteString => return Some(VariantScalarTypeId::ByteString),
288 crate::DataTypeId::XmlElement => return Some(VariantScalarTypeId::XmlElement),
289 crate::DataTypeId::NodeId => return Some(VariantScalarTypeId::NodeId),
290 crate::DataTypeId::ExpandedNodeId => {
291 return Some(VariantScalarTypeId::ExpandedNodeId)
292 }
293 crate::DataTypeId::StatusCode => return Some(VariantScalarTypeId::StatusCode),
294 crate::DataTypeId::QualifiedName => {
295 return Some(VariantScalarTypeId::QualifiedName)
296 }
297 crate::DataTypeId::LocalizedText => {
298 return Some(VariantScalarTypeId::LocalizedText)
299 }
300 crate::DataTypeId::Structure | crate::DataTypeId::Decimal => {
303 return Some(VariantScalarTypeId::ExtensionObject)
304 }
305 crate::DataTypeId::DataValue => return Some(VariantScalarTypeId::DataValue),
306 crate::DataTypeId::DiagnosticInfo => {
307 return Some(VariantScalarTypeId::DiagnosticInfo)
308 }
309 crate::DataTypeId::Enumeration => return Some(VariantScalarTypeId::Int32),
310 crate::DataTypeId::BaseDataType => return Some(VariantScalarTypeId::Variant),
312 _ => (),
313 }
314 }
315 let parent = self.parent_ids.get(id)?;
316 self.get_builtin_type(parent)
317 }
318}
319
320impl TypeInfo {
321 pub fn from_type_definition(
323 value: DataTypeDefinition,
324 name: String,
325 encoding_ids: Option<EncodingIds>,
326 is_abstract: bool,
327 node_id: &NodeId,
328 parent_ids: &ParentIds,
329 ) -> Result<Self, String> {
330 match value {
331 DataTypeDefinition::Structure(d) => {
332 let Some(encoding_ids) = encoding_ids else {
333 return Err("Missing encoding IDs for structured type".to_owned());
334 };
335 let mut fields =
336 Vec::with_capacity(d.fields.as_ref().map(|f| f.len()).unwrap_or_default());
337 let mut fields_by_name = HashMap::with_capacity(fields.len());
338 for (idx, v) in d.fields.into_iter().flatten().enumerate() {
339 let Some(builtin) = parent_ids.get_builtin_type(&v.data_type) else {
340 return Err(format!(
341 "Failed to resolve type id {node_id} to scalar type"
342 ));
343 };
344 let f = ParsedStructureField::from_field(v, builtin)?;
345 fields_by_name.insert(f.name.clone(), idx);
346 fields.push(f);
347 }
348
349 Ok(Self::Struct(Arc::new(StructTypeInfo {
350 structure_type: d.structure_type,
351 fields,
352 encoding_ids,
353 is_abstract,
354 node_id: node_id.clone(),
355 index_by_name: fields_by_name,
356 name,
357 })))
358 }
359 DataTypeDefinition::Enum(d) => Ok(Self::Enum(Arc::new(EnumTypeInfo {
360 variants: d
361 .fields
362 .into_iter()
363 .flatten()
364 .map(|v| (v.value, v))
365 .collect(),
366 }))),
367 }
368 }
369}
370
371#[derive(Debug)]
372pub struct DataTypeTree {
374 struct_types: HashMap<NodeId, Arc<StructTypeInfo>>,
375 enum_types: HashMap<NodeId, Arc<EnumTypeInfo>>,
376 other_types: HashMap<NodeId, Arc<GenericTypeInfo>>,
377 parent_ids: ParentIds,
378 encoding_to_data_type: HashMap<NodeId, NodeId>,
379}
380
381impl DataTypeTree {
382 pub fn new(parent_ids: ParentIds) -> Self {
386 Self {
387 struct_types: HashMap::new(),
388 enum_types: HashMap::new(),
389 other_types: HashMap::new(),
390 parent_ids,
391 encoding_to_data_type: HashMap::new(),
392 }
393 }
394
395 pub fn add_type(&mut self, id: NodeId, info: impl Into<TypeInfo>) {
397 let info = info.into();
398 match info {
399 TypeInfo::Enum(arc) => {
400 self.enum_types.insert(id.clone(), arc);
401 }
402 TypeInfo::Struct(arc) => {
403 self.encoding_to_data_type
404 .insert(arc.encoding_ids.binary_id.clone(), id.clone());
405 self.encoding_to_data_type
406 .insert(arc.encoding_ids.json_id.clone(), id.clone());
407 self.encoding_to_data_type
408 .insert(arc.encoding_ids.xml_id.clone(), id.clone());
409 self.struct_types.insert(id.clone(), arc);
410 }
411 TypeInfo::Primitive(arc) => {
412 self.other_types.insert(id.clone(), arc);
413 }
414 }
415 }
416
417 pub fn get_type<'a>(&'a self, id: &NodeId) -> Option<TypeInfoRef<'a>> {
419 if let Some(d) = self.struct_types.get(id) {
420 Some(TypeInfoRef::Struct(d))
421 } else if let Some(d) = self.enum_types.get(id) {
422 Some(TypeInfoRef::Enum(d))
423 } else {
424 self.other_types.get(id).map(TypeInfoRef::Primitive)
425 }
426 }
427
428 pub fn get_struct_type(&self, id: &NodeId) -> Option<&Arc<StructTypeInfo>> {
430 self.struct_types.get(id)
431 }
432
433 pub fn parent_ids_mut(&mut self) -> &mut ParentIds {
435 &mut self.parent_ids
436 }
437
438 pub fn parent_ids(&self) -> &ParentIds {
440 &self.parent_ids
441 }
442
443 pub fn encoding_to_data_type(&self) -> &HashMap<NodeId, NodeId> {
445 &self.encoding_to_data_type
446 }
447}