use opcua_types::{
CallMethodRequest, CallMethodResult, DiagnosticBits, DiagnosticInfo, NodeId, StatusCode,
Variant,
};
use super::IntoResult;
#[derive(Debug)]
pub struct MethodCall {
object_id: NodeId,
method_id: NodeId,
arguments: Vec<Variant>,
diagnostic_bits: DiagnosticBits,
status: StatusCode,
argument_results: Vec<StatusCode>,
outputs: Vec<Variant>,
diagnostic_info: Option<DiagnosticInfo>,
}
impl MethodCall {
pub(crate) fn new(request: CallMethodRequest, diagnostic_bits: DiagnosticBits) -> Self {
Self {
object_id: request.object_id,
method_id: request.method_id,
arguments: request.input_arguments.unwrap_or_default(),
status: StatusCode::BadMethodInvalid,
argument_results: Vec::new(),
outputs: Vec::new(),
diagnostic_bits,
diagnostic_info: None,
}
}
pub fn set_argument_error(&mut self, argument_results: Vec<StatusCode>) {
self.argument_results = argument_results;
self.status = StatusCode::BadInvalidArgument;
}
pub fn set_status(&mut self, status: StatusCode) {
self.status = status;
}
pub fn set_outputs(&mut self, outputs: Vec<Variant>) {
self.outputs = outputs;
}
pub fn arguments(&self) -> &[Variant] {
&self.arguments
}
pub fn method_id(&self) -> &NodeId {
&self.method_id
}
pub fn object_id(&self) -> &NodeId {
&self.object_id
}
pub fn status(&self) -> StatusCode {
self.status
}
pub fn diagnostic_bits(&self) -> DiagnosticBits {
self.diagnostic_bits
}
pub fn set_diagnostic_info(&mut self, diagnostic_info: DiagnosticInfo) {
self.diagnostic_info = Some(diagnostic_info);
}
}
impl IntoResult for MethodCall {
type Result = CallMethodResult;
fn into_result(self) -> (Self::Result, Option<DiagnosticInfo>) {
(
CallMethodResult {
status_code: self.status,
input_argument_diagnostic_infos: None,
input_argument_results: if !self.argument_results.is_empty() {
Some(self.argument_results)
} else {
None
},
output_arguments: Some(self.outputs),
},
self.diagnostic_info,
)
}
}
#[macro_export]
macro_rules! load_method_args {
($call:expr, $($type:ident),+) => {
{
let mut arguments = $call.arguments().iter();
(move || {
Ok($(
match arguments.next().map(|v| v.convert(VariantTypeId::Scalar(VariantScalarTypeId::$type))) {
Some(Variant::$type(val)) => val,
_ => return Err(StatusCode::BadInvalidArgument),
}
),*)
})()
}
};
}