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 {
144 pub is_abstract: bool,
146}
147
148impl GenericTypeInfo {
149 pub fn new(is_abstract: bool) -> Self {
151 Self { is_abstract }
152 }
153}
154
155#[derive(Debug)]
156pub enum TypeInfo {
158 Enum(Arc<EnumTypeInfo>),
160 Struct(Arc<StructTypeInfo>),
162 Primitive(Arc<GenericTypeInfo>),
164}
165
166#[derive(Debug)]
167pub enum TypeInfoRef<'a> {
169 Enum(&'a Arc<EnumTypeInfo>),
171 Struct(&'a Arc<StructTypeInfo>),
173 Primitive(&'a Arc<GenericTypeInfo>),
175}
176
177impl From<StructTypeInfo> for TypeInfo {
178 fn from(value: StructTypeInfo) -> Self {
179 Self::Struct(Arc::new(value))
180 }
181}
182
183impl From<EnumTypeInfo> for TypeInfo {
184 fn from(value: EnumTypeInfo) -> Self {
185 Self::Enum(Arc::new(value))
186 }
187}
188
189impl From<GenericTypeInfo> for TypeInfo {
190 fn from(value: GenericTypeInfo) -> Self {
191 Self::Primitive(Arc::new(value))
192 }
193}
194
195#[derive(Debug)]
196pub struct ParentIds {
198 parent_ids: HashMap<NodeId, NodeId>,
199}
200
201impl Default for ParentIds {
202 fn default() -> Self {
203 Self::new()
204 }
205}
206
207pub enum DataTypeVariant {
209 Enumeration,
211 Structure,
213 Primitive,
215}
216
217impl ParentIds {
218 pub fn new() -> Self {
220 Self {
221 parent_ids: HashMap::new(),
222 }
223 }
224
225 pub fn add_type(&mut self, node_id: NodeId, parent_id: NodeId) {
227 self.parent_ids.insert(node_id, parent_id);
228 }
229
230 pub fn get_data_type_variant(&self, id: &NodeId) -> Option<DataTypeVariant> {
233 if let Ok(t) = id.as_data_type_id() {
234 match t {
235 crate::DataTypeId::Boolean
236 | crate::DataTypeId::SByte
237 | crate::DataTypeId::Byte
238 | crate::DataTypeId::Int16
239 | crate::DataTypeId::UInt16
240 | crate::DataTypeId::Int32
241 | crate::DataTypeId::UInt32
242 | crate::DataTypeId::Int64
243 | crate::DataTypeId::UInt64
244 | crate::DataTypeId::Float
245 | crate::DataTypeId::Double
246 | crate::DataTypeId::String
247 | crate::DataTypeId::DateTime
248 | crate::DataTypeId::Guid
249 | crate::DataTypeId::ByteString
250 | crate::DataTypeId::XmlElement
251 | crate::DataTypeId::NodeId
252 | crate::DataTypeId::ExpandedNodeId
253 | crate::DataTypeId::StatusCode
254 | crate::DataTypeId::QualifiedName
255 | crate::DataTypeId::LocalizedText
256 | crate::DataTypeId::DataValue
257 | crate::DataTypeId::DiagnosticInfo
258 | crate::DataTypeId::BaseDataType => return Some(DataTypeVariant::Primitive),
259 crate::DataTypeId::Structure | crate::DataTypeId::Decimal => {
260 return Some(DataTypeVariant::Structure)
261 }
262 crate::DataTypeId::Enumeration => return Some(DataTypeVariant::Enumeration),
263 _ => (),
264 }
265 }
266
267 let parent = self.parent_ids.get(id)?;
268 self.get_data_type_variant(parent)
269 }
270
271 pub fn get_builtin_type(&self, id: &NodeId) -> Option<VariantScalarTypeId> {
274 if let Ok(t) = id.as_data_type_id() {
275 match t {
276 crate::DataTypeId::Boolean => return Some(VariantScalarTypeId::Boolean),
277 crate::DataTypeId::SByte => return Some(VariantScalarTypeId::SByte),
278 crate::DataTypeId::Byte => return Some(VariantScalarTypeId::Byte),
279 crate::DataTypeId::Int16 => return Some(VariantScalarTypeId::Int16),
280 crate::DataTypeId::UInt16 => return Some(VariantScalarTypeId::UInt16),
281 crate::DataTypeId::Int32 => return Some(VariantScalarTypeId::Int32),
282 crate::DataTypeId::UInt32 => return Some(VariantScalarTypeId::UInt32),
283 crate::DataTypeId::Int64 => return Some(VariantScalarTypeId::Int64),
284 crate::DataTypeId::UInt64 => return Some(VariantScalarTypeId::UInt64),
285 crate::DataTypeId::Float => return Some(VariantScalarTypeId::Float),
286 crate::DataTypeId::Double => return Some(VariantScalarTypeId::Double),
287 crate::DataTypeId::String => return Some(VariantScalarTypeId::String),
288 crate::DataTypeId::DateTime => return Some(VariantScalarTypeId::DateTime),
289 crate::DataTypeId::Guid => return Some(VariantScalarTypeId::Guid),
290 crate::DataTypeId::ByteString => return Some(VariantScalarTypeId::ByteString),
291 crate::DataTypeId::XmlElement => return Some(VariantScalarTypeId::XmlElement),
292 crate::DataTypeId::NodeId => return Some(VariantScalarTypeId::NodeId),
293 crate::DataTypeId::ExpandedNodeId => {
294 return Some(VariantScalarTypeId::ExpandedNodeId)
295 }
296 crate::DataTypeId::StatusCode => return Some(VariantScalarTypeId::StatusCode),
297 crate::DataTypeId::QualifiedName => {
298 return Some(VariantScalarTypeId::QualifiedName)
299 }
300 crate::DataTypeId::LocalizedText => {
301 return Some(VariantScalarTypeId::LocalizedText)
302 }
303 crate::DataTypeId::Structure | crate::DataTypeId::Decimal => {
306 return Some(VariantScalarTypeId::ExtensionObject)
307 }
308 crate::DataTypeId::DataValue => return Some(VariantScalarTypeId::DataValue),
309 crate::DataTypeId::DiagnosticInfo => {
310 return Some(VariantScalarTypeId::DiagnosticInfo)
311 }
312 crate::DataTypeId::Enumeration => return Some(VariantScalarTypeId::Int32),
313 crate::DataTypeId::BaseDataType => return Some(VariantScalarTypeId::Variant),
315 _ => (),
316 }
317 }
318 let parent = self.parent_ids.get(id)?;
319 self.get_builtin_type(parent)
320 }
321}
322
323impl TypeInfo {
324 pub fn from_type_definition(
326 value: DataTypeDefinition,
327 name: String,
328 encoding_ids: Option<EncodingIds>,
329 is_abstract: bool,
330 node_id: &NodeId,
331 parent_ids: &ParentIds,
332 ) -> Result<Self, String> {
333 match value {
334 DataTypeDefinition::Structure(d) => {
335 let Some(encoding_ids) = encoding_ids else {
336 return Err("Missing encoding IDs for structured type".to_owned());
337 };
338 let mut fields =
339 Vec::with_capacity(d.fields.as_ref().map(|f| f.len()).unwrap_or_default());
340 let mut fields_by_name = HashMap::with_capacity(fields.len());
341 for (idx, v) in d.fields.into_iter().flatten().enumerate() {
342 let Some(builtin) = parent_ids.get_builtin_type(&v.data_type) else {
343 return Err(format!(
344 "Failed to resolve type id {node_id} to scalar type"
345 ));
346 };
347 let f = ParsedStructureField::from_field(v, builtin)?;
348 fields_by_name.insert(f.name.clone(), idx);
349 fields.push(f);
350 }
351
352 Ok(Self::Struct(Arc::new(StructTypeInfo {
353 structure_type: d.structure_type,
354 fields,
355 encoding_ids,
356 is_abstract,
357 node_id: node_id.clone(),
358 index_by_name: fields_by_name,
359 name,
360 })))
361 }
362 DataTypeDefinition::Enum(d) => Ok(Self::Enum(Arc::new(EnumTypeInfo {
363 variants: d
364 .fields
365 .into_iter()
366 .flatten()
367 .map(|v| (v.value, v))
368 .collect(),
369 }))),
370 }
371 }
372}
373
374#[derive(Debug)]
375pub struct DataTypeTree {
377 struct_types: HashMap<NodeId, Arc<StructTypeInfo>>,
378 enum_types: HashMap<NodeId, Arc<EnumTypeInfo>>,
379 other_types: HashMap<NodeId, Arc<GenericTypeInfo>>,
380 parent_ids: ParentIds,
381 encoding_to_data_type: HashMap<NodeId, NodeId>,
382}
383
384impl DataTypeTree {
385 pub fn new(parent_ids: ParentIds) -> Self {
389 Self {
390 struct_types: HashMap::new(),
391 enum_types: HashMap::new(),
392 other_types: HashMap::new(),
393 parent_ids,
394 encoding_to_data_type: HashMap::new(),
395 }
396 }
397
398 pub fn add_type(&mut self, id: NodeId, info: impl Into<TypeInfo>) {
400 let info = info.into();
401 match info {
402 TypeInfo::Enum(arc) => {
403 self.enum_types.insert(id.clone(), arc);
404 }
405 TypeInfo::Struct(arc) => {
406 self.encoding_to_data_type
407 .insert(arc.encoding_ids.binary_id.clone(), id.clone());
408 self.encoding_to_data_type
409 .insert(arc.encoding_ids.json_id.clone(), id.clone());
410 self.encoding_to_data_type
411 .insert(arc.encoding_ids.xml_id.clone(), id.clone());
412 self.struct_types.insert(id.clone(), arc);
413 }
414 TypeInfo::Primitive(arc) => {
415 self.other_types.insert(id.clone(), arc);
416 }
417 }
418 }
419
420 pub fn get_type<'a>(&'a self, id: &NodeId) -> Option<TypeInfoRef<'a>> {
422 if let Some(d) = self.struct_types.get(id) {
423 Some(TypeInfoRef::Struct(d))
424 } else if let Some(d) = self.enum_types.get(id) {
425 Some(TypeInfoRef::Enum(d))
426 } else {
427 self.other_types.get(id).map(TypeInfoRef::Primitive)
428 }
429 }
430
431 pub fn get_struct_type(&self, id: &NodeId) -> Option<&Arc<StructTypeInfo>> {
433 self.struct_types.get(id)
434 }
435
436 pub fn parent_ids_mut(&mut self) -> &mut ParentIds {
438 &mut self.parent_ids
439 }
440
441 pub fn parent_ids(&self) -> &ParentIds {
443 &self.parent_ids
444 }
445
446 pub fn encoding_to_data_type(&self) -> &HashMap<NodeId, NodeId> {
448 &self.encoding_to_data_type
449 }
450}