use std::convert::{Into, TryFrom};
use std::sync::{Arc, Mutex};
use opcua_types::service_types::VariableAttributes;
use crate::{
address_space::{
AccessLevel, base::Base,
node::{Node, NodeBase},
UserAccessLevel,
},
callbacks::{AttributeGetter, AttributeSetter},
};
node_builder_impl!(VariableBuilder, Variable);
node_builder_impl_component_of!(VariableBuilder);
node_builder_impl_property_of!(VariableBuilder);
impl VariableBuilder {
pub fn value<V>(mut self, value: V) -> Self where V: Into<Variant> {
let _ = self.node.set_value(NumericRange::None, value);
self
}
pub fn data_type<T>(mut self, data_type: T) -> Self where T: Into<NodeId> {
self.node.set_data_type(data_type);
self
}
pub fn historizing(mut self, historizing: bool) -> Self {
self.node.set_historizing(historizing);
self
}
pub fn access_level(mut self, access_level: AccessLevel) -> Self {
self.node.set_access_level(access_level);
self
}
pub fn user_access_level(mut self, user_access_level: UserAccessLevel) -> Self {
self.node.set_user_access_level(user_access_level);
self
}
pub fn value_rank(mut self, value_rank: i32) -> Self {
self.node.set_value_rank(value_rank);
self
}
pub fn array_dimensions(mut self, array_dimensions: &[u32]) -> Self {
self.node.set_array_dimensions(array_dimensions);
self
}
pub fn writable(mut self) -> Self {
self.node.set_user_access_level(self.node.user_access_level() | UserAccessLevel::CURRENT_WRITE);
self.node.set_access_level(self.node.access_level() | AccessLevel::CURRENT_WRITE);
self
}
pub fn history_readable(mut self) -> Self {
self.node.set_user_access_level(self.node.user_access_level() | UserAccessLevel::HISTORY_READ);
self.node.set_access_level(self.node.access_level() | AccessLevel::HISTORY_READ);
self
}
pub fn history_updatable(mut self) -> Self {
self.node.set_user_access_level(self.node.user_access_level() | UserAccessLevel::HISTORY_WRITE);
self.node.set_access_level(self.node.access_level() | AccessLevel::HISTORY_WRITE);
self
}
pub fn minimum_sampling_interval(mut self, minimum_sampling_interval: f64) -> Self {
self.node.set_minimum_sampling_interval(minimum_sampling_interval);
self
}
pub fn value_getter(mut self, getter: Arc<Mutex<dyn AttributeGetter + Send>>) -> Self {
self.node.set_value_getter(getter);
self
}
pub fn value_setter(mut self, setter: Arc<Mutex<dyn AttributeSetter + Send>>) -> Self {
self.node.set_value_setter(setter);
self
}
pub fn has_type_definition<T>(self, type_id: T) -> Self where T: Into<NodeId> {
self.reference(type_id, ReferenceTypeId::HasTypeDefinition, ReferenceDirection::Forward)
}
pub fn has_modelling_rule<T>(self, type_id: T) -> Self where T: Into<NodeId> {
self.reference(type_id, ReferenceTypeId::HasModellingRule, ReferenceDirection::Forward)
}
}
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Variable {
base: Base,
data_type: NodeId,
historizing: bool,
value_rank: i32,
value: DataValue,
access_level: u8,
user_access_level: u8,
array_dimensions: Option<Vec<u32>>,
minimum_sampling_interval: Option<f64>,
#[derivative(Debug = "ignore")]
value_setter: Option<Arc<Mutex<dyn AttributeSetter + Send>>>,
#[derivative(Debug = "ignore")]
value_getter: Option<Arc<Mutex<dyn AttributeGetter + Send>>>,
}
impl Default for Variable {
fn default() -> Self {
Self {
base: Base::new(NodeClass::Variable, &NodeId::null(), "", ""),
data_type: NodeId::null(),
historizing: false,
value_rank: -1,
value: Variant::Empty.into(),
access_level: UserAccessLevel::CURRENT_READ.bits(),
user_access_level: AccessLevel::CURRENT_READ.bits(),
array_dimensions: None,
minimum_sampling_interval: None,
value_getter: None,
value_setter: None,
}
}
}
node_base_impl!(Variable);
impl Node for Variable {
fn get_attribute_max_age(&self, timestamps_to_return: TimestampsToReturn, attribute_id: AttributeId, index_range: NumericRange, data_encoding: &QualifiedName, max_age: f64) -> Option<DataValue> {
match attribute_id {
AttributeId::Value => Some(self.value(timestamps_to_return, index_range, data_encoding, max_age)),
AttributeId::DataType => Some(self.data_type().into()),
AttributeId::Historizing => Some(self.historizing().into()),
AttributeId::ValueRank => Some(self.value_rank().into()),
AttributeId::AccessLevel => Some(self.access_level().bits().into()),
AttributeId::UserAccessLevel => Some(self.user_access_level().bits().into()),
AttributeId::ArrayDimensions => self.array_dimensions().map(|v| Variant::from(v).into()),
AttributeId::MinimumSamplingInterval => self.minimum_sampling_interval().map(|v| v.into()),
_ => self.base.get_attribute_max_age(timestamps_to_return, attribute_id, index_range, data_encoding, max_age)
}
}
fn set_attribute(&mut self, attribute_id: AttributeId, value: Variant) -> Result<(), StatusCode> {
match attribute_id {
AttributeId::DataType => if let Variant::NodeId(v) = value {
self.set_data_type(*v);
Ok(())
} else {
Err(StatusCode::BadTypeMismatch)
},
AttributeId::Historizing => if let Variant::Boolean(v) = value {
self.set_historizing(v);
Ok(())
} else {
Err(StatusCode::BadTypeMismatch)
},
AttributeId::ValueRank => if let Variant::Int32(v) = value {
self.set_value_rank(v);
Ok(())
} else {
Err(StatusCode::BadTypeMismatch)
},
AttributeId::Value => {
self.set_value(NumericRange::None, value)
}
AttributeId::AccessLevel => if let Variant::Byte(v) = value {
self.set_access_level(AccessLevel::from_bits_truncate(v));
Ok(())
} else {
Err(StatusCode::BadTypeMismatch)
},
AttributeId::UserAccessLevel => if let Variant::Byte(v) = value {
self.set_user_access_level(UserAccessLevel::from_bits_truncate(v));
Ok(())
} else {
Err(StatusCode::BadTypeMismatch)
},
AttributeId::ArrayDimensions => {
let array_dimensions = <Vec<u32>>::try_from(&value);
if let Ok(array_dimensions) = array_dimensions {
self.set_array_dimensions(&array_dimensions);
Ok(())
} else {
Err(StatusCode::BadTypeMismatch)
}
}
AttributeId::MinimumSamplingInterval => if let Variant::Double(v) = value {
self.set_minimum_sampling_interval(v);
Ok(())
} else {
Err(StatusCode::BadTypeMismatch)
},
_ => self.base.set_attribute(attribute_id, value)
}
}
}
impl Variable {
pub fn new<R, S, V>(node_id: &NodeId, browse_name: R, display_name: S, value: V) -> Variable
where R: Into<QualifiedName>,
S: Into<LocalizedText>,
V: Into<Variant>
{
let value = value.into();
let data_type = value.scalar_data_type().or_else(|| value.array_data_type());
if let Some(data_type) = data_type {
Variable::new_data_value(node_id, browse_name, display_name, data_type, None, None, value)
} else {
panic!("Data type cannot be inferred from the value, use another constructor such as new_data_value")
}
}
pub fn from_attributes<S>(node_id: &NodeId, browse_name: S, attributes: VariableAttributes) -> Result<Self, ()>
where S: Into<QualifiedName>
{
let mandatory_attributes = AttributesMask::DISPLAY_NAME | AttributesMask::ACCESS_LEVEL | AttributesMask::USER_ACCESS_LEVEL |
AttributesMask::DATA_TYPE | AttributesMask::HISTORIZING | AttributesMask::VALUE | AttributesMask::VALUE_RANK;
let mask = AttributesMask::from_bits(attributes.specified_attributes).ok_or(())?;
if mask.contains(mandatory_attributes) {
let mut node = Self::new_data_value(node_id, browse_name, attributes.display_name, attributes.data_type, None, None, attributes.value);
node.set_value_rank(attributes.value_rank);
node.set_historizing(attributes.historizing);
node.set_access_level(AccessLevel::from_bits_truncate(attributes.access_level));
node.set_user_access_level(UserAccessLevel::from_bits_truncate(attributes.user_access_level));
if mask.contains(AttributesMask::DESCRIPTION) {
node.set_description(attributes.description);
}
if mask.contains(AttributesMask::WRITE_MASK) {
node.set_write_mask(WriteMask::from_bits_truncate(attributes.write_mask));
}
if mask.contains(AttributesMask::USER_WRITE_MASK) {
node.set_user_write_mask(WriteMask::from_bits_truncate(attributes.user_write_mask));
}
if mask.contains(AttributesMask::ARRAY_DIMENSIONS) {
node.set_array_dimensions(attributes.array_dimensions.unwrap().as_slice());
}
if mask.contains(AttributesMask::MINIMUM_SAMPLING_INTERVAL) {
node.set_minimum_sampling_interval(attributes.minimum_sampling_interval);
}
Ok(node)
} else {
error!("Variable cannot be created from attributes - missing mandatory values");
Err(())
}
}
pub fn new_data_value<S, R, N, V>(node_id: &NodeId, browse_name: R, display_name: S, data_type: N, value_rank: Option<i32>, array_dimensions: Option<u32>, value: V) -> Variable
where R: Into<QualifiedName>,
S: Into<LocalizedText>,
N: Into<NodeId>,
V: Into<Variant>
{
let value = value.into();
let array_dimensions = if let Some(array_dimensions) = array_dimensions {
Some(vec![array_dimensions])
} else {
match value {
Variant::Array(ref array) => {
if !array.has_dimensions() {
Some(vec![array.values.len() as u32])
} else {
Some(array.dimensions.iter().map(|v| *v as u32).collect::<Vec<u32>>())
}
}
_ => None
}
};
let value_rank = if let Some(value_rank) = value_rank {
value_rank
} else {
if let Some(ref array_dimensions) = array_dimensions {
array_dimensions.len() as i32
} else {
-1
}
};
let builder = VariableBuilder::new(node_id, browse_name, display_name)
.user_access_level(UserAccessLevel::CURRENT_READ)
.access_level(AccessLevel::CURRENT_READ)
.data_type(data_type)
.historizing(false)
.value_rank(value_rank)
.value(value);
let builder = if let Some(ref array_dimensions) = array_dimensions {
builder.array_dimensions(array_dimensions.as_slice())
} else {
builder
};
builder.build()
}
pub fn is_valid(&self) -> bool {
!self.data_type.is_null() && self.base.is_valid()
}
pub fn value(&self, timestamps_to_return: TimestampsToReturn, index_range: NumericRange, data_encoding: &QualifiedName, max_age: f64) -> DataValue {
use std::i32;
if let Some(ref value_getter) = self.value_getter {
let mut value_getter = value_getter.lock().unwrap();
value_getter.get(&self.node_id(), timestamps_to_return, AttributeId::Value, index_range, data_encoding, max_age).unwrap().unwrap()
} else {
let data_value = &self.value;
let mut result = DataValue {
server_picoseconds: data_value.server_picoseconds.clone(),
server_timestamp: data_value.server_timestamp.clone(),
source_picoseconds: data_value.source_picoseconds.clone(),
source_timestamp: data_value.source_timestamp.clone(),
value: None,
status: None,
};
if let Some(ref value) = data_value.value {
match value.range_of(index_range) {
Ok(value) => {
result.value = Some(value);
result.status = data_value.status.clone();
}
Err(err) => {
result.status = Some(err);
}
}
}
if max_age > 0.0 && max_age <= i32::MAX as f64 {
result.server_timestamp = Some(DateTime::now());
}
result
}
}
pub fn set_value<V>(&mut self, index_range: NumericRange, value: V) -> Result<(), StatusCode> where V: Into<Variant> {
let mut value = value.into();
match self.value_rank {
-3 | -2 | 1 => {
if self.data_type == DataTypeId::Byte.into() {
if let Variant::ByteString(_) = value {
value = value.to_byte_array();
}
}
}
_ => { }
};
if let Some(ref value_setter) = self.value_setter {
let mut value_setter = value_setter.lock().unwrap();
value_setter.set(&self.node_id(), AttributeId::Value, index_range, value.into())
} else {
let now = DateTime::now();
if index_range.has_range() {
self.set_value_range(value, index_range, StatusCode::Good, &now, &now)
} else {
self.set_value_direct(value, StatusCode::Good, &now, &now)
}
}
}
pub fn set_value_range(&mut self, value: Variant, index_range: NumericRange, status_code: StatusCode, server_timestamp: &DateTime, source_timestamp: &DateTime) -> Result<(), StatusCode> {
match self.value.value {
Some(ref mut full_value) => {
full_value.set_range_of(index_range, &value)?;
self.value.status = Some(status_code);
self.value.server_timestamp = Some(server_timestamp.clone());
self.value.source_timestamp = Some(source_timestamp.clone());
Ok(())
}
None => Err(StatusCode::BadIndexRangeInvalid)
}
}
pub fn set_value_direct<V>(&mut self, value: V, status_code: StatusCode, server_timestamp: &DateTime, source_timestamp: &DateTime) -> Result<(), StatusCode> where V: Into<Variant> {
self.value.value = Some(value.into());
self.value.status = Some(status_code);
self.value.server_timestamp = Some(server_timestamp.clone());
self.value.source_timestamp = Some(source_timestamp.clone());
Ok(())
}
pub fn set_value_getter(&mut self, value_getter: Arc<Mutex<dyn AttributeGetter + Send>>) {
self.value_getter = Some(value_getter);
}
pub fn set_value_setter(&mut self, value_setter: Arc<Mutex<dyn AttributeSetter + Send>>) {
self.value_setter = Some(value_setter);
}
pub fn minimum_sampling_interval(&self) -> Option<f64> {
self.minimum_sampling_interval.clone()
}
pub fn set_minimum_sampling_interval(&mut self, minimum_sampling_interval: f64) {
self.minimum_sampling_interval = Some(minimum_sampling_interval);
}
pub fn is_readable(&self) -> bool {
self.access_level().contains(AccessLevel::CURRENT_READ)
}
pub fn is_writable(&self) -> bool {
self.access_level().contains(AccessLevel::CURRENT_WRITE)
}
pub fn set_writable(&mut self, writable: bool) {
let mut access_level = self.access_level();
if writable {
access_level.insert(AccessLevel::CURRENT_WRITE);
} else {
access_level.remove(AccessLevel::CURRENT_WRITE);
}
self.set_access_level(access_level);
}
pub fn access_level(&self) -> AccessLevel {
AccessLevel::from_bits_truncate(self.access_level)
}
pub fn set_access_level(&mut self, access_level: AccessLevel) {
self.access_level = access_level.bits();
}
pub fn is_user_readable(&self) -> bool {
self.user_access_level().contains(UserAccessLevel::CURRENT_READ)
}
pub fn is_user_writable(&self) -> bool {
self.user_access_level().contains(UserAccessLevel::CURRENT_WRITE)
}
pub fn user_access_level(&self) -> UserAccessLevel {
UserAccessLevel::from_bits_truncate(self.user_access_level)
}
pub fn set_user_access_level(&mut self, user_access_level: UserAccessLevel) {
self.user_access_level = user_access_level.bits();
}
pub fn value_rank(&self) -> i32 {
self.value_rank
}
pub fn set_value_rank(&mut self, value_rank: i32) {
self.value_rank = value_rank;
}
pub fn historizing(&self) -> bool {
self.historizing
}
pub fn set_historizing(&mut self, historizing: bool) {
self.historizing = historizing;
}
pub fn array_dimensions(&self) -> Option<Vec<u32>> {
self.array_dimensions.clone()
}
pub fn set_array_dimensions(&mut self, array_dimensions: &[u32]) {
self.array_dimensions = Some(array_dimensions.to_vec());
}
pub fn data_type(&self) -> NodeId {
self.data_type.clone()
}
pub fn set_data_type<T>(&mut self, data_type: T) where T: Into<NodeId> {
self.data_type = data_type.into();
}
}