1use opcua_types::{
7 AttributeId, AttributesMask, DataEncoding, DataValue, NumericRange, StatusCode,
8 TimestampsToReturn, Variant, ViewAttributes,
9};
10use tracing::error;
11
12use crate::FromAttributesError;
13
14use super::{base::Base, node::Node, node::NodeBase, EventNotifier};
15
16node_builder_impl!(ViewBuilder, View);
17
18node_builder_impl_generates_event!(ViewBuilder);
19
20impl ViewBuilder {
21 pub fn contains_no_loops(mut self, contains_no_loops: bool) -> Self {
23 self.node.set_contains_no_loops(contains_no_loops);
24 self
25 }
26
27 pub fn event_notifier(mut self, event_notifier: EventNotifier) -> Self {
29 self.node.set_event_notifier(event_notifier);
30 self
31 }
32
33 pub fn write_mask(mut self, write_mask: WriteMask) -> Self {
35 self.node.set_write_mask(write_mask);
36 self
37 }
38}
39
40#[derive(Debug)]
42pub struct View {
43 pub(super) base: Base,
44 pub(super) event_notifier: EventNotifier,
45 pub(super) contains_no_loops: bool,
46}
47
48impl Default for View {
49 fn default() -> Self {
50 Self {
51 base: Base::new(NodeClass::View, &NodeId::null(), "", ""),
52 event_notifier: EventNotifier::empty(),
53 contains_no_loops: true,
54 }
55 }
56}
57
58node_base_impl!(View);
59
60impl Node for View {
61 fn get_attribute_max_age(
62 &self,
63 timestamps_to_return: TimestampsToReturn,
64 attribute_id: AttributeId,
65 index_range: &NumericRange,
66 data_encoding: &DataEncoding,
67 max_age: f64,
68 ) -> Option<DataValue> {
69 match attribute_id {
70 AttributeId::EventNotifier => Some(Variant::from(self.event_notifier().bits()).into()),
71 AttributeId::ContainsNoLoops => Some(Variant::from(self.contains_no_loops()).into()),
72 _ => self.base.get_attribute_max_age(
73 timestamps_to_return,
74 attribute_id,
75 index_range,
76 data_encoding,
77 max_age,
78 ),
79 }
80 }
81
82 fn set_attribute(
83 &mut self,
84 attribute_id: AttributeId,
85 value: Variant,
86 ) -> Result<(), StatusCode> {
87 match attribute_id {
88 AttributeId::EventNotifier => {
89 if let Variant::Byte(v) = value {
90 self.set_event_notifier(EventNotifier::from_bits_truncate(v));
91 Ok(())
92 } else {
93 Err(StatusCode::BadTypeMismatch)
94 }
95 }
96 AttributeId::ContainsNoLoops => {
97 if let Variant::Boolean(v) = value {
98 self.set_contains_no_loops(v);
99 Ok(())
100 } else {
101 Err(StatusCode::BadTypeMismatch)
102 }
103 }
104 _ => self.base.set_attribute(attribute_id, value),
105 }
106 }
107}
108
109impl View {
110 pub fn new(
112 node_id: &NodeId,
113 browse_name: impl Into<QualifiedName>,
114 display_name: impl Into<LocalizedText>,
115 event_notifier: EventNotifier,
116 contains_no_loops: bool,
117 ) -> View {
118 View {
119 base: Base::new(NodeClass::View, node_id, browse_name, display_name),
120 event_notifier,
121 contains_no_loops,
122 }
123 }
124
125 pub fn new_full(base: Base, event_notifier: EventNotifier, contains_no_loops: bool) -> Self {
127 Self {
128 base,
129 event_notifier,
130 contains_no_loops,
131 }
132 }
133
134 pub fn from_attributes(
136 node_id: &NodeId,
137 browse_name: impl Into<QualifiedName>,
138 attributes: ViewAttributes,
139 ) -> Result<Self, FromAttributesError> {
140 let mandatory_attributes = AttributesMask::DISPLAY_NAME
141 | AttributesMask::EVENT_NOTIFIER
142 | AttributesMask::CONTAINS_NO_LOOPS;
143 let mask = AttributesMask::from_bits_truncate(attributes.specified_attributes);
144 if mask.contains(mandatory_attributes) {
145 let event_notifier = EventNotifier::from_bits_truncate(attributes.event_notifier);
146 let mut node = Self::new(
147 node_id,
148 browse_name,
149 attributes.display_name,
150 event_notifier,
151 attributes.contains_no_loops,
152 );
153 if mask.contains(AttributesMask::DESCRIPTION) {
154 node.set_description(attributes.description);
155 }
156 if mask.contains(AttributesMask::WRITE_MASK) {
157 node.set_write_mask(WriteMask::from_bits_truncate(attributes.write_mask));
158 }
159 if mask.contains(AttributesMask::USER_WRITE_MASK) {
160 node.set_user_write_mask(WriteMask::from_bits_truncate(attributes.user_write_mask));
161 }
162 Ok(node)
163 } else {
164 error!("View cannot be created from attributes - missing mandatory values");
165 Err(FromAttributesError::MissingMandatoryValues)
166 }
167 }
168
169 pub fn is_valid(&self) -> bool {
171 self.base.is_valid()
172 }
173
174 pub fn event_notifier(&self) -> EventNotifier {
176 self.event_notifier
177 }
178
179 pub fn set_event_notifier(&mut self, event_notifier: EventNotifier) {
181 self.event_notifier = event_notifier;
182 }
183
184 pub fn contains_no_loops(&self) -> bool {
186 self.contains_no_loops
187 }
188
189 pub fn set_contains_no_loops(&mut self, contains_no_loops: bool) {
191 self.contains_no_loops = contains_no_loops
192 }
193}