1use chrono::{DateTime, Utc};
4use roxmltree::{Document, Node};
5
6use crate::{
7 ext::{
8 children_with_name, first_child_with_name_opt, value_from_attr, value_from_attr_opt,
9 value_from_contents, NodeExt,
10 },
11 FromValue, XmlError, XmlLoad,
12};
13
14use super::opc_ua_types::Variant;
15
16#[derive(Debug)]
17pub struct NodeSet2 {
21 pub node_set: Option<UANodeSet>,
23 pub node_set_changes: Option<UANodeSetChanges>,
25 pub node_set_changes_status: Option<UANodeSetChangesStatus>,
27}
28
29pub fn load_nodeset2_file(document: &str) -> Result<NodeSet2, XmlError> {
31 let document = Document::parse(document).map_err(|e| XmlError {
32 span: 0..1,
33 error: crate::error::XmlErrorInner::Xml(e),
34 })?;
35 let root = document.root();
36 Ok(NodeSet2 {
37 node_set: first_child_with_name_opt(&root, "UANodeSet")?,
38 node_set_changes: first_child_with_name_opt(&root, "UANodeSetChanges")?,
39 node_set_changes_status: first_child_with_name_opt(&root, "UANodeSetChangesStatus")?,
40 })
41}
42
43#[derive(Debug)]
44pub enum UANode {
46 Object(UAObject),
48 Variable(UAVariable),
50 Method(UAMethod),
52 View(UAView),
54 ObjectType(UAObjectType),
56 VariableType(UAVariableType),
58 DataType(UADataType),
60 ReferenceType(UAReferenceType),
62}
63
64impl UANode {
65 pub(crate) fn from_node(node: &Node<'_, '_>) -> Result<Option<Self>, XmlError> {
66 Ok(Some(match node.tag_name().name() {
67 "UAObject" => Self::Object(XmlLoad::load(node)?),
68 "UAVariable" => Self::Variable(XmlLoad::load(node)?),
69 "UAMethod" => Self::Method(XmlLoad::load(node)?),
70 "UAView" => Self::View(XmlLoad::load(node)?),
71 "UAObjectType" => Self::ObjectType(XmlLoad::load(node)?),
72 "UAVariableType" => Self::VariableType(XmlLoad::load(node)?),
73 "UADataType" => Self::DataType(XmlLoad::load(node)?),
74 "UAReferenceType" => Self::ReferenceType(XmlLoad::load(node)?),
75 _ => return Ok(None),
76 }))
77 }
78
79 pub fn base(&self) -> &UANodeBase {
81 match self {
82 UANode::Object(n) => &n.base.base,
83 UANode::Variable(n) => &n.base.base,
84 UANode::Method(n) => &n.base.base,
85 UANode::View(n) => &n.base.base,
86 UANode::ObjectType(n) => &n.base.base,
87 UANode::VariableType(n) => &n.base.base,
88 UANode::DataType(n) => &n.base.base,
89 UANode::ReferenceType(n) => &n.base.base,
90 }
91 }
92}
93
94#[derive(Debug, Default)]
95pub struct UANodeSet {
97 pub namespace_uris: Option<UriTable>,
99 pub server_uris: Option<UriTable>,
101 pub models: Option<ModelTable>,
103 pub aliases: Option<AliasTable>,
105 pub nodes: Vec<UANode>,
107 pub last_modified: Option<DateTime<Utc>>,
109}
110
111impl<'input> XmlLoad<'input> for UANodeSet {
112 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
113 let mut namespace_uris = None;
117 let mut server_uris = None;
118 let mut models = None;
119 let mut aliases = None;
120 let mut nodes = Vec::new();
121 for child in node.children() {
122 match child.tag_name().name() {
123 "NamespaceUris" => namespace_uris = Some(XmlLoad::load(&child)?),
124 "ServerUris" => server_uris = Some(XmlLoad::load(&child)?),
125 "Models" => models = Some(XmlLoad::load(&child)?),
126 "Aliases" => aliases = Some(XmlLoad::load(&child)?),
127 _ => {
128 if let Some(node) = UANode::from_node(&child)? {
129 nodes.push(node);
130 }
131 }
132 }
133 }
134
135 Ok(Self {
136 namespace_uris,
137 server_uris,
138 models,
139 aliases,
140 nodes,
141 last_modified: value_from_attr_opt(node, "LastModified")?,
142 })
143 }
144}
145
146#[derive(Debug)]
147pub struct UANodeSetChanges {
149 pub namespace_uris: Option<UriTable>,
151 pub server_uris: Option<UriTable>,
153 pub aliases: Option<AliasTable>,
155 pub nodes_to_add: Option<NodesToAdd>,
157 pub references_to_add: Option<ReferencesToChange>,
159 pub nodes_to_delete: Option<NodesToDelete>,
161 pub references_to_delete: Option<ReferencesToChange>,
163 pub last_modified: Option<DateTime<Utc>>,
165 pub transaction_id: String,
167 pub accept_all_or_nothing: bool,
170}
171
172impl<'input> XmlLoad<'input> for UANodeSetChanges {
173 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
174 Ok(Self {
175 namespace_uris: first_child_with_name_opt(node, "NamespaceUris")?,
176 server_uris: first_child_with_name_opt(node, "ServerUris")?,
177 aliases: first_child_with_name_opt(node, "Aliases")?,
178 nodes_to_add: first_child_with_name_opt(node, "NodesToAdd")?,
179 references_to_add: first_child_with_name_opt(node, "ReferencesToAdd")?,
180 nodes_to_delete: first_child_with_name_opt(node, "NodesToDelete")?,
181 references_to_delete: first_child_with_name_opt(node, "ReferencesToDelete")?,
182 last_modified: value_from_attr_opt(node, "LastModified")?,
183 transaction_id: value_from_attr(node, "TransactionId")?,
184 accept_all_or_nothing: value_from_attr_opt(node, "AcceptAllOrNothing")?
185 .unwrap_or(false),
186 })
187 }
188}
189
190#[derive(Debug)]
191pub struct UANodeSetChangesStatus {
193 pub nodes_to_add: Option<NodeSetStatusList>,
195 pub references_to_add: Option<NodeSetStatusList>,
197 pub nodes_to_delete: Option<NodeSetStatusList>,
199 pub references_to_delete: Option<NodeSetStatusList>,
201 pub last_modified: Option<DateTime<Utc>>,
203 pub transaction_id: String,
205}
206
207impl<'input> XmlLoad<'input> for UANodeSetChangesStatus {
208 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
209 Ok(Self {
210 nodes_to_add: first_child_with_name_opt(node, "NodesToAdd")?,
211 references_to_add: first_child_with_name_opt(node, "ReferencesToAdd")?,
212 nodes_to_delete: first_child_with_name_opt(node, "NodesToDelete")?,
213 references_to_delete: first_child_with_name_opt(node, "ReferencesToDelete")?,
214 last_modified: value_from_attr_opt(node, "LastModified")?,
215 transaction_id: value_from_attr(node, "TransactionId")?,
216 })
217 }
218}
219
220#[derive(Debug)]
221pub struct NodesToAdd {
223 pub nodes: Vec<UANode>,
225}
226
227impl<'input> XmlLoad<'input> for NodesToAdd {
228 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
229 Ok(Self {
230 nodes: node
231 .children()
232 .filter_map(|n| UANode::from_node(&n).transpose())
233 .collect::<Result<Vec<_>, _>>()?,
234 })
235 }
236}
237
238#[derive(Debug)]
239pub struct NodeToDelete {
241 pub node_id: NodeId,
243 pub delete_reverse_references: bool,
246}
247
248impl<'input> XmlLoad<'input> for NodeToDelete {
249 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
250 Ok(Self {
251 node_id: NodeId::load(node)?,
252 delete_reverse_references: value_from_attr_opt(node, "DeleteReverseReferences")?
253 .unwrap_or(true),
254 })
255 }
256}
257
258#[derive(Debug)]
259pub struct NodesToDelete {
261 pub nodes: Vec<NodeToDelete>,
263}
264
265impl<'input> XmlLoad<'input> for NodesToDelete {
266 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
267 Ok(Self {
268 nodes: children_with_name(node, "Node")?,
269 })
270 }
271}
272
273#[derive(Debug)]
274pub struct ReferenceChange {
276 pub node_id: NodeId,
278 pub source: NodeId,
280 pub reference_type: NodeId,
282 pub is_forward: bool,
284}
285
286impl<'input> XmlLoad<'input> for ReferenceChange {
287 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
288 Ok(Self {
289 node_id: NodeId::load(node)?,
290 source: value_from_attr(node, "Source")?,
291 reference_type: value_from_attr(node, "ReferenceType")?,
292 is_forward: value_from_attr_opt(node, "IsForward")?.unwrap_or(true),
293 })
294 }
295}
296
297#[derive(Debug)]
298pub struct ReferencesToChange {
300 pub references: Vec<ReferenceChange>,
302}
303
304impl<'input> XmlLoad<'input> for ReferencesToChange {
305 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
306 Ok(Self {
307 references: children_with_name(node, "Reference")?,
308 })
309 }
310}
311
312#[derive(Debug)]
313pub struct NodeSetStatus {
315 pub status: String,
317 pub code: u64,
319}
320
321impl<'input> XmlLoad<'input> for NodeSetStatus {
322 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
323 Ok(Self {
324 status: String::load(node)?,
325 code: value_from_attr_opt(node, "Code")?.unwrap_or(0),
326 })
327 }
328}
329
330#[derive(Debug)]
331pub struct NodeSetStatusList {
333 pub statuses: Vec<NodeSetStatus>,
335}
336
337impl<'input> XmlLoad<'input> for NodeSetStatusList {
338 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
339 Ok(Self {
340 statuses: children_with_name(node, "Status")?,
341 })
342 }
343}
344
345#[derive(Debug)]
346pub struct UriTable {
348 pub uris: Vec<String>,
350}
351
352impl<'input> XmlLoad<'input> for UriTable {
353 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
354 Ok(Self {
355 uris: node
356 .with_name("Uri")
357 .map(|v| v.try_contents().map(|v| v.to_owned()))
358 .collect::<Result<Vec<_>, _>>()?,
359 })
360 }
361}
362
363macro_rules! value_wrapper {
364 ($key:ident, $doc:expr, $ty:ident) => {
365 #[derive(Debug, Default, Clone)]
366 #[doc = $doc]
367 pub struct $key(pub $ty);
368
369 impl FromValue for $key {
370 fn from_value(node: &Node<'_, '_>, attr: &str, v: &str) -> Result<Self, XmlError> {
371 Ok(Self($ty::from_value(node, attr, v)?))
372 }
373 }
374 };
375}
376
377#[derive(Debug, Clone)]
378pub struct ModelTableEntry {
380 pub role_permissions: Option<ListOfRolePermissions>,
382 pub required_model: Vec<ModelTableEntry>,
384 pub model_uri: String,
386 pub version: Option<String>,
388 pub publication_date: Option<DateTime<Utc>>,
390 pub access_restrictions: AccessRestriction,
392}
393
394impl<'input> XmlLoad<'input> for ModelTableEntry {
395 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
396 Ok(Self {
397 role_permissions: first_child_with_name_opt(node, "RolePermissions")?,
398 required_model: children_with_name(node, "RequiredModel")?,
399 model_uri: node.try_attribute("ModelUri")?.to_owned(),
400 version: node.attribute("Version").map(|v| v.to_owned()),
401 publication_date: value_from_attr_opt(node, "PublicationDate")?,
402 access_restrictions: value_from_attr_opt(node, "AccessRestrictions")?
403 .unwrap_or(AccessRestriction(0)),
404 })
405 }
406}
407
408#[derive(Debug, Clone)]
409pub struct ModelTable {
411 pub models: Vec<ModelTableEntry>,
413}
414
415impl<'input> XmlLoad<'input> for ModelTable {
416 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
417 Ok(Self {
418 models: children_with_name(node, "Model")?,
419 })
420 }
421}
422
423value_wrapper!(NodeId, "An OPC-UA node ID or alias", String);
424value_wrapper!(
425 QualifiedName,
426 "An OPC-UA QualifiedName on the form Name:Index",
427 String
428);
429value_wrapper!(Locale, "A text locale", String);
430value_wrapper!(WriteMask, "A node write mask", u32);
431value_wrapper!(EventNotifier, "Node event notifier", u8);
432value_wrapper!(ValueRank, "Variable value rank", i32);
433value_wrapper!(AccessRestriction, "Access restriction flags", u8);
434value_wrapper!(
435 ArrayDimensions,
436 "Array dimensions as a comma separated list of lengths",
437 String
438);
439value_wrapper!(
440 Duration,
441 "Duration as a floating point number of seconds",
442 f64
443);
444value_wrapper!(AccessLevel, "Access level flags", u8);
445
446impl FromValue for chrono::DateTime<Utc> {
447 fn from_value(node: &Node<'_, '_>, attr: &str, v: &str) -> Result<Self, XmlError> {
448 let v = chrono::DateTime::parse_from_rfc3339(v)
449 .map_err(|e| XmlError::parse_date_time(node, attr, e))?;
450 Ok(v.with_timezone(&Utc))
451 }
452}
453
454#[derive(Debug)]
455pub struct NodeIdAlias {
457 pub id: NodeId,
459 pub alias: String,
461}
462
463impl<'input> XmlLoad<'input> for NodeIdAlias {
464 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
465 Ok(Self {
466 id: NodeId::load(node)?,
467 alias: node.try_attribute("Alias")?.to_owned(),
468 })
469 }
470}
471
472#[derive(Debug, Default)]
473pub struct AliasTable {
475 pub aliases: Vec<NodeIdAlias>,
477}
478
479impl<'input> XmlLoad<'input> for AliasTable {
480 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
481 Ok(Self {
482 aliases: children_with_name(node, "Alias")?,
483 })
484 }
485}
486
487#[derive(Debug, Default, Clone)]
488pub struct LocalizedText {
490 pub text: String,
492 pub locale: Locale,
494}
495impl<'input> XmlLoad<'input> for LocalizedText {
496 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
497 Ok(Self {
498 text: node.text().map(|v| v.to_owned()).unwrap_or_default(),
499 locale: value_from_attr_opt(node, "Locale")?.unwrap_or_else(|| Locale("".to_owned())),
500 })
501 }
502}
503
504#[derive(Debug, Clone)]
505pub struct SymbolicName {
507 pub names: Vec<String>,
509}
510
511impl FromValue for SymbolicName {
512 fn from_value(_node: &Node<'_, '_>, _attr: &str, v: &str) -> Result<Self, XmlError> {
513 Ok(Self {
514 names: v.split_whitespace().map(|v| v.to_owned()).collect(),
515 })
516 }
517}
518
519#[derive(Debug)]
520pub struct Reference {
522 pub node_id: NodeId,
524 pub reference_type: NodeId,
526 pub is_forward: bool,
528}
529
530impl<'input> XmlLoad<'input> for Reference {
531 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
532 Ok(Self {
533 node_id: value_from_contents(node)?,
534 reference_type: value_from_attr(node, "ReferenceType")?,
535 is_forward: value_from_attr_opt(node, "IsForward")?.unwrap_or(true),
536 })
537 }
538}
539
540#[derive(Debug)]
541pub struct ListOfReferences {
543 pub references: Vec<Reference>,
545}
546impl<'input> XmlLoad<'input> for ListOfReferences {
547 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
548 Ok(Self {
549 references: children_with_name(node, "Reference")?,
550 })
551 }
552}
553
554#[derive(Debug, Clone)]
555pub struct RolePermission {
557 pub node_id: NodeId,
559 pub permissions: u64,
561}
562
563impl<'input> XmlLoad<'input> for RolePermission {
564 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
565 Ok(Self {
566 node_id: value_from_contents(node)?,
567 permissions: value_from_attr_opt(node, "Permissions")?.unwrap_or(0),
568 })
569 }
570}
571
572#[derive(Debug, Clone)]
573pub struct ListOfRolePermissions {
575 pub role_permissions: Vec<RolePermission>,
577}
578impl<'input> XmlLoad<'input> for ListOfRolePermissions {
579 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
580 Ok(Self {
581 role_permissions: children_with_name(node, "RolePermission")?,
582 })
583 }
584}
585
586#[derive(Debug)]
587pub enum ReleaseStatus {
589 Released,
591 Draft,
593 Deprecated,
595}
596
597impl FromValue for ReleaseStatus {
598 fn from_value(node: &Node<'_, '_>, attr: &str, v: &str) -> Result<Self, XmlError> {
599 match v {
600 "Released" => Ok(Self::Released),
601 "Draft" => Ok(Self::Draft),
602 "Deprecated" => Ok(Self::Deprecated),
603 r => Err(XmlError::other(
604 node,
605 &format!("Unexpected value for {attr}: {r}"),
606 )),
607 }
608 }
609}
610
611#[derive(Debug)]
612pub struct UANodeBase {
614 pub display_names: Vec<LocalizedText>,
616 pub description: Vec<LocalizedText>,
618 pub category: Vec<String>,
620 pub documentation: Option<String>,
622 pub references: Option<ListOfReferences>,
624 pub role_permissions: Option<ListOfRolePermissions>,
626 pub node_id: NodeId,
628 pub browse_name: QualifiedName,
630 pub write_mask: WriteMask,
632 pub user_write_mask: WriteMask,
634 pub access_restrictions: AccessRestriction,
636 pub symbolic_name: Option<SymbolicName>,
638 pub release_status: ReleaseStatus,
640}
641
642impl<'input> XmlLoad<'input> for UANodeBase {
643 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
644 Ok(Self {
645 display_names: children_with_name(node, "DisplayName")?,
646 description: children_with_name(node, "Description")?,
647 category: children_with_name(node, "Category")?,
648 documentation: first_child_with_name_opt(node, "Documentation")?,
649 references: first_child_with_name_opt(node, "References")?,
650 role_permissions: first_child_with_name_opt(node, "RolePermissions")?,
651 node_id: value_from_attr(node, "NodeId")?,
652 browse_name: value_from_attr(node, "BrowseName")?,
653 write_mask: value_from_attr_opt(node, "WriteMask")?.unwrap_or(WriteMask(0)),
654 user_write_mask: value_from_attr_opt(node, "UserWriteMask")?.unwrap_or(WriteMask(0)),
655 access_restrictions: value_from_attr_opt(node, "AccessRestrictions")?
656 .unwrap_or(AccessRestriction(0)),
657 symbolic_name: value_from_attr_opt(node, "SymbolicName")?,
658 release_status: value_from_attr_opt(node, "ReleaseStatus")?
659 .unwrap_or(ReleaseStatus::Released),
660 })
661 }
662}
663
664#[derive(Debug)]
665pub struct UAInstance {
667 pub base: UANodeBase,
669 pub parent_node_id: Option<NodeId>,
671}
672
673impl<'input> XmlLoad<'input> for UAInstance {
674 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
675 Ok(Self {
676 base: UANodeBase::load(node)?,
677 parent_node_id: value_from_attr_opt(node, "ParentNodeId")?,
678 })
679 }
680}
681
682#[derive(Debug)]
683pub struct UAObject {
685 pub base: UAInstance,
687 pub event_notifier: EventNotifier,
689}
690
691impl<'input> XmlLoad<'input> for UAObject {
692 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
693 Ok(Self {
694 base: UAInstance::load(node)?,
695 event_notifier: value_from_attr_opt(node, "EventNotifier")?.unwrap_or(EventNotifier(0)),
696 })
697 }
698}
699
700#[derive(Debug)]
701pub struct Value(pub Variant);
703
704impl<'input> XmlLoad<'input> for Value {
705 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
706 Ok(Self(
707 node.children()
708 .find(|n| !n.tag_name().name().is_empty())
709 .map(|n| Variant::load(&n))
710 .transpose()?
711 .ok_or_else(|| XmlError::other(node, "Empty value, expected variant"))?,
712 ))
713 }
714}
715
716#[derive(Debug)]
717pub struct UAVariable {
719 pub base: UAInstance,
721 pub value: Option<Value>,
723 pub data_type: NodeId,
725 pub value_rank: ValueRank,
727 pub array_dimensions: ArrayDimensions,
729 pub access_level: AccessLevel,
731 pub user_access_level: AccessLevel,
733 pub minimum_sampling_interval: Duration,
735 pub historizing: bool,
737}
738
739impl<'input> XmlLoad<'input> for UAVariable {
740 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
741 Ok(Self {
742 base: UAInstance::load(node)?,
743 value: first_child_with_name_opt(node, "Value")?,
744 data_type: value_from_attr_opt(node, "DataType")?
745 .unwrap_or_else(|| NodeId("i=24".to_owned())),
746 value_rank: value_from_attr_opt(node, "ValueRank")?.unwrap_or(ValueRank(-1)),
747 array_dimensions: value_from_attr_opt(node, "ArrayDimensions")?
748 .unwrap_or_else(|| ArrayDimensions("".to_owned())),
749 access_level: value_from_attr_opt(node, "AccessLevel")?.unwrap_or(AccessLevel(1)),
750 user_access_level: value_from_attr_opt(node, "UserAccessLevel")?
751 .unwrap_or(AccessLevel(1)),
752 minimum_sampling_interval: value_from_attr_opt(node, "MinimumSamplingInterval")?
753 .unwrap_or(Duration(0.0)),
754 historizing: value_from_attr_opt(node, "Historizing")?.unwrap_or(false),
755 })
756 }
757}
758
759#[derive(Debug)]
760pub struct UAMethodArgument {
762 pub name: Option<String>,
764 pub descriptions: Vec<LocalizedText>,
766}
767
768impl<'input> XmlLoad<'input> for UAMethodArgument {
769 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
770 Ok(Self {
771 name: first_child_with_name_opt(node, "Name")?,
772 descriptions: children_with_name(node, "Description")?,
773 })
774 }
775}
776
777#[derive(Debug)]
778pub struct UAMethod {
780 pub base: UAInstance,
782 pub arguments: Vec<UAMethodArgument>,
784 pub executable: bool,
786 pub user_executable: bool,
788 pub method_declaration_id: Option<NodeId>,
790}
791
792impl<'input> XmlLoad<'input> for UAMethod {
793 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
794 Ok(Self {
795 base: UAInstance::load(node)?,
796 arguments: children_with_name(node, "ArgumentDescription")?,
797 executable: value_from_attr_opt(node, "Executable")?.unwrap_or(false),
798 user_executable: value_from_attr_opt(node, "UserExecutable")?.unwrap_or(false),
799 method_declaration_id: value_from_attr_opt(node, "MethodDeclarationId")?,
800 })
801 }
802}
803
804#[derive(Debug)]
805pub struct StructureTranslationType {
807 pub text: Vec<LocalizedText>,
809 pub name: String,
811}
812
813impl<'input> XmlLoad<'input> for StructureTranslationType {
814 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
815 Ok(Self {
816 text: children_with_name(node, "Text")?,
817 name: value_from_attr(node, "Name")?,
818 })
819 }
820}
821
822#[derive(Debug)]
823pub enum TranslationType {
825 Text(Vec<LocalizedText>),
827 Field(Vec<StructureTranslationType>),
829 None,
831}
832
833impl<'input> XmlLoad<'input> for TranslationType {
834 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
835 let texts = children_with_name(node, "Text")?;
836 if !texts.is_empty() {
837 return Ok(Self::Text(texts));
838 }
839 let fields = children_with_name(node, "Field")?;
840 if !fields.is_empty() {
841 return Ok(Self::Field(fields));
842 }
843 Ok(Self::None)
844 }
845}
846
847#[derive(Debug)]
848pub struct UAView {
850 pub base: UAInstance,
852 pub contains_no_loops: bool,
854 pub event_notifier: EventNotifier,
856}
857
858impl<'input> XmlLoad<'input> for UAView {
859 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
860 Ok(Self {
861 base: UAInstance::load(node)?,
862 contains_no_loops: value_from_attr_opt(node, "ContainsNoLoops")?.unwrap_or(false),
863 event_notifier: value_from_attr(node, "EventNotifier")?,
864 })
865 }
866}
867
868#[derive(Debug)]
869pub struct UAType {
871 pub base: UANodeBase,
873 pub is_abstract: bool,
875}
876
877impl<'input> XmlLoad<'input> for UAType {
878 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
879 Ok(Self {
880 base: UANodeBase::load(node)?,
881 is_abstract: value_from_attr_opt(node, "IsAbstract")?.unwrap_or(false),
882 })
883 }
884}
885
886#[derive(Debug)]
887pub struct UAObjectType {
889 pub base: UAType,
891}
892
893impl<'input> XmlLoad<'input> for UAObjectType {
894 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
895 Ok(Self {
896 base: UAType::load(node)?,
897 })
898 }
899}
900
901#[derive(Debug)]
902pub struct UAVariableType {
904 pub base: UAType,
906 pub value: Option<Value>,
908 pub data_type: NodeId,
910 pub value_rank: ValueRank,
912 pub array_dimensions: ArrayDimensions,
914}
915
916impl<'input> XmlLoad<'input> for UAVariableType {
917 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
918 Ok(Self {
919 base: UAType::load(node)?,
920 value: first_child_with_name_opt(node, "Value")?,
921 data_type: value_from_attr_opt(node, "DataType")?
922 .unwrap_or_else(|| NodeId("i=24".to_owned())),
923 value_rank: value_from_attr_opt(node, "ValueRank")?.unwrap_or(ValueRank(-1)),
924 array_dimensions: value_from_attr_opt(node, "ArrayDimensions")?
925 .unwrap_or_else(|| ArrayDimensions("".to_owned())),
926 })
927 }
928}
929
930#[derive(Debug)]
931pub enum DataTypePurpose {
933 Normal,
935 ServicesOnly,
937 CodeGenerator,
939}
940
941impl FromValue for DataTypePurpose {
942 fn from_value(node: &Node<'_, '_>, attr: &str, v: &str) -> Result<Self, XmlError> {
943 match v {
944 "Normal" => Ok(Self::Normal),
945 "ServicesOnly" => Ok(Self::ServicesOnly),
946 "CodeGenerator" => Ok(Self::CodeGenerator),
947 r => Err(XmlError::other(
948 node,
949 &format!("Unexpected value for {attr}: {r}"),
950 )),
951 }
952 }
953}
954
955#[derive(Debug, Clone)]
956pub struct DataTypeField {
958 pub display_names: Vec<LocalizedText>,
960 pub descriptions: Vec<LocalizedText>,
962 pub name: String,
964 pub symbolic_name: Option<SymbolicName>,
966 pub data_type: NodeId,
968 pub value_rank: ValueRank,
970 pub array_dimensions: ArrayDimensions,
972 pub max_string_length: u64,
974 pub value: i64,
976 pub is_optional: bool,
978 pub allow_sub_types: bool,
980}
981
982impl<'input> XmlLoad<'input> for DataTypeField {
983 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
984 Ok(Self {
985 display_names: children_with_name(node, "DisplayName")?,
986 descriptions: children_with_name(node, "Description")?,
987 name: value_from_attr(node, "Name")?,
988 symbolic_name: value_from_attr_opt(node, "SymbolicName")?,
989 data_type: value_from_attr_opt(node, "DataType")?
990 .unwrap_or_else(|| NodeId("i=24".to_owned())),
991 value_rank: value_from_attr_opt(node, "ValueRank")?.unwrap_or(ValueRank(-1)),
992 array_dimensions: value_from_attr_opt(node, "ArrayDimensions")?
993 .unwrap_or_else(|| ArrayDimensions("".to_owned())),
994 max_string_length: value_from_attr_opt(node, "MaxStringLength")?.unwrap_or(0),
995 value: value_from_attr_opt(node, "Value")?.unwrap_or(-1),
996 is_optional: value_from_attr_opt(node, "IsOptional")?.unwrap_or(false),
997 allow_sub_types: value_from_attr_opt(node, "AllowSubTypes")?.unwrap_or(false),
998 })
999 }
1000}
1001
1002#[derive(Debug, Clone)]
1003pub struct DataTypeDefinition {
1005 pub fields: Vec<DataTypeField>,
1007 pub name: QualifiedName,
1009 pub symbolic_name: SymbolicName,
1011 pub is_union: bool,
1013 pub is_option_set: bool,
1015}
1016
1017impl<'input> XmlLoad<'input> for DataTypeDefinition {
1018 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
1019 Ok(Self {
1020 fields: children_with_name(node, "Field")?,
1021 name: value_from_attr(node, "Name")?,
1022 symbolic_name: value_from_attr_opt(node, "SymbolicName")?
1023 .unwrap_or_else(|| SymbolicName { names: Vec::new() }),
1024 is_union: value_from_attr_opt(node, "IsUnion")?.unwrap_or(false),
1025 is_option_set: value_from_attr_opt(node, "IsOptionSet")?.unwrap_or(false),
1026 })
1027 }
1028}
1029
1030#[derive(Debug)]
1031pub struct UADataType {
1033 pub base: UAType,
1035 pub definition: Option<DataTypeDefinition>,
1037 pub purpose: DataTypePurpose,
1039}
1040
1041impl<'input> XmlLoad<'input> for UADataType {
1042 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
1043 Ok(Self {
1044 base: UAType::load(node)?,
1045 definition: first_child_with_name_opt(node, "Definition")?,
1046 purpose: value_from_attr_opt(node, "Purpose")?.unwrap_or(DataTypePurpose::Normal),
1047 })
1048 }
1049}
1050
1051#[derive(Debug)]
1052pub struct UAReferenceType {
1054 pub base: UAType,
1056 pub inverse_names: Vec<LocalizedText>,
1058 pub symmetric: bool,
1060}
1061
1062impl<'input> XmlLoad<'input> for UAReferenceType {
1063 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
1064 Ok(Self {
1065 base: UAType::load(node)?,
1066 inverse_names: children_with_name(node, "InverseName")?,
1067 symmetric: value_from_attr_opt(node, "Symmetric")?.unwrap_or(false),
1068 })
1069 }
1070}