use tango_omniorb as orb;
use crate::backend::{DevCommandBackend, DevGetCommandInfoBackend};
use crate::data::{Data, DataLayout, DataLayoutView, DataStruct, DataView};
use crate::dev::{CommandInfo, DevState, DisplayLevel};
use crate::error::{Error, ErrorKind, Result};
use crate::array::MdView;
use super::convert::{data_kind_from_type, opt_str_if, S_UNINITIALIZED};
pub fn command_data_to_any(buf: Data<'_>) -> Result<orb::CORBA_Any> {
let mut any = orb::CORBA_Any::default();
match buf.as_view() {
DataView::Void => (),
DataView::Bool(DataLayoutView::Scalar(&val)) => any.insert_boolean(val),
DataView::Octet(DataLayoutView::Scalar(&val)) => any.insert_octet(val),
DataView::UShort(DataLayoutView::Scalar(&val)) => any.insert_ushort(val),
DataView::Short(DataLayoutView::Scalar(&val)) => any.insert_short(val),
DataView::ULong(DataLayoutView::Scalar(&val)) => any.insert_ulong(val),
DataView::Long(DataLayoutView::Scalar(&val)) => any.insert_long(val),
DataView::ULong64(DataLayoutView::Scalar(&val)) => any.insert_ulonglong(val),
DataView::Long64(DataLayoutView::Scalar(&val)) => any.insert_longlong(val),
DataView::Float(DataLayoutView::Scalar(&val)) => any.insert_float(val),
DataView::Double(DataLayoutView::Scalar(&val)) => any.insert_double(val),
DataView::State(DataLayoutView::Scalar(&val)) => any.insert(orb::Tango_DevState::from(val)),
DataView::String(DataLayoutView::Scalar(val)) => {
any.insert_string_move(orb::CORBA_String::try_from(&**val)
.map_err(|()| Error::new(ErrorKind::InvalidData)
.with_append_description("String cannot be converted to CORBA::String")
.with_append_description(format_args!("{val:?}")))?);
}
DataView::Bool(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarBooleanArray>()));
}
DataView::Octet(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarCharArray>()));
}
DataView::UShort(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarUShortArray>()));
}
DataView::Short(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarShortArray>()));
}
DataView::ULong(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarULongArray>()));
}
DataView::Long(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarLongArray>()));
}
DataView::ULong64(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarULong64Array>()));
}
DataView::Long64(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarLong64Array>()));
}
DataView::Float(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarFloatArray>()));
}
DataView::Double(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarDoubleArray>()));
}
DataView::State(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(view.as_raw_slice().iter()
.map(|&s| orb::Tango_DevState::from(s))
.collect::<orb::Tango_DevVarStateArray>()));
}
DataView::String(DataLayoutView::Spectrum(view)) => {
let mut arr = orb::CppBox::new(orb::Tango_DevVarStringArray(orb::CORBA_Sequence::with_capacity(view.raw_len())));
for val in view.as_raw_slice() {
match orb::CORBA_String::try_from(&**val) {
Ok(s) => arr.push(s),
Err(_) => return Err(Error::new(ErrorKind::InvalidData)
.with_append_description("String cannot be converted to CORBA::String")
.with_append_description(format_args!("{val:?}"))),
};
}
any.insert_move(arr);
}
DataView::Struct(data) => {
if data.len() != 2 {
return Err(Error::new(ErrorKind::InvalidData)
.with_append_description("Struct cannot be converted to CORBA::Any")
.with_append_description(format_args!("{data:?}")));
}
let svalue = match data.get(1).unwrap() {
DataView::String(DataLayoutView::Spectrum(view)) => {
let mut arr = orb::Tango_DevVarStringArray(orb::CORBA_Sequence::with_capacity(view.raw_len()));
for val in view.as_raw_slice() {
match orb::CORBA_String::try_from(&**val) {
Ok(s) => arr.push(s),
Err(_) => return Err(Error::new(ErrorKind::InvalidData)
.with_append_description("String cannot be converted to CORBA::String")
.with_append_description(format_args!("{val:?}"))),
};
}
arr
}
_ => return Err(Error::new(ErrorKind::InvalidData)
.with_append_description("Data struct cannot be converted to CORBA::Any because second field should be a string sequence")
.with_append_description(format_args!("{data:?}")))
};
match data.get(0).unwrap() {
DataView::Long(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(orb::Tango_DevVarLongStringArray {
lvalue: view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarLongArray>(),
svalue,
}));
}
DataView::Double(DataLayoutView::Spectrum(view)) => {
any.insert_move(orb::CppBox::new(orb::Tango_DevVarDoubleStringArray {
dvalue: view.as_raw_slice().iter().copied()
.collect::<orb::Tango_DevVarDoubleArray>(),
svalue,
}));
}
_ => return Err(Error::new(ErrorKind::InvalidData)
.with_append_description("Struct cannot be converted to CORBA::Any because first field should be a long/double sequence")
.with_append_description(format_args!("{data:?}")))
}
}
_ => return Err(Error::new(ErrorKind::InvalidData)
.with_append_description("Cannot be converted to CORBA::Any")
.with_append_description(format_args!("{buf:?}")))
}
Ok(any)
}
#[derive(Debug)]
pub struct DevCommandFromAny {
any: orb::CORBA_Any,
}
impl DevCommandFromAny {
#[inline]
pub fn new(any: orb::CORBA_Any) -> Self {
Self {
any,
}
}
fn get_inner(&self) -> Option<Data<'_>> {
let tc = self.any.type_code()?;
let data = match tc.kind() {
orb::CORBA_TypeCodeKind::Null => Data::Void,
orb::CORBA_TypeCodeKind::Boolean =>
Data::Bool(DataLayout::Scalar(self.any.extract_boolean()?)),
orb::CORBA_TypeCodeKind::UShort =>
Data::UShort(DataLayout::Scalar(self.any.extract_ushort()?)),
orb::CORBA_TypeCodeKind::Short =>
Data::Short(DataLayout::Scalar(self.any.extract_short()?)),
orb::CORBA_TypeCodeKind::ULong =>
Data::ULong(DataLayout::Scalar(self.any.extract_ulong()?)),
orb::CORBA_TypeCodeKind::Long =>
Data::Long(DataLayout::Scalar(self.any.extract_long()?)),
orb::CORBA_TypeCodeKind::ULongLong =>
Data::ULong64(DataLayout::Scalar(self.any.extract_ulonglong()?)),
orb::CORBA_TypeCodeKind::LongLong =>
Data::Long64(DataLayout::Scalar(self.any.extract_longlong()?)),
orb::CORBA_TypeCodeKind::Float =>
Data::Float(DataLayout::Scalar(self.any.extract_float()?)),
orb::CORBA_TypeCodeKind::Double =>
Data::Double(DataLayout::Scalar(self.any.extract_double()?)),
orb::CORBA_TypeCodeKind::Enum => {
Data::State(DataLayout::Scalar(self.any.extract::<orb::Tango_DevState>()?.into()))
}
orb::CORBA_TypeCodeKind::String => {
Data::String(DataLayout::Scalar(self.any.extract_string_borrow()?.to_string_lossy()))
}
orb::CORBA_TypeCodeKind::Alias => {
let tc_seq = tc.content_type()?;
if tc_seq.kind() != orb::CORBA_TypeCodeKind::Sequence {
return None;
}
let tc_item = tc_seq.content_type()?;
match tc_item.kind() {
orb::CORBA_TypeCodeKind::Boolean => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarBooleanArray>()?;
Data::Bool(DataLayout::SpectrumView(MdView::from(&arr[..])))
}
orb::CORBA_TypeCodeKind::UShort => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarUShortArray>()?;
Data::UShort(DataLayout::SpectrumView(MdView::from(&arr[..])))
}
orb::CORBA_TypeCodeKind::Short => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarShortArray>()?;
Data::Short(DataLayout::SpectrumView(MdView::from(&arr[..])))
}
orb::CORBA_TypeCodeKind::ULong => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarULongArray>()?;
Data::ULong(DataLayout::SpectrumView(MdView::from(&arr[..])))
}
orb::CORBA_TypeCodeKind::Long => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarLongArray>()?;
Data::Long(DataLayout::SpectrumView(MdView::from(&arr[..])))
}
orb::CORBA_TypeCodeKind::ULongLong => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarULong64Array>()?;
Data::ULong64(DataLayout::SpectrumView(MdView::from(&arr[..])))
}
orb::CORBA_TypeCodeKind::LongLong => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarLong64Array>()?;
Data::Long64(DataLayout::SpectrumView(MdView::from(&arr[..])))
}
orb::CORBA_TypeCodeKind::Float => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarFloatArray>()?;
Data::Float(DataLayout::SpectrumView(MdView::from(&arr[..])))
}
orb::CORBA_TypeCodeKind::Double => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarDoubleArray>()?;
Data::Double(DataLayout::SpectrumView(MdView::from(&arr[..])))
}
orb::CORBA_TypeCodeKind::Enum => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarStateArray>()?;
Data::State(DataLayout::Spectrum(arr.iter()
.map(|&s| Into::<DevState>::into(s))
.collect::<Vec<_>>()
.into()))
}
orb::CORBA_TypeCodeKind::String => {
let arr = self.any.extract_borrow::<orb::Tango_DevVarStringArray>()?;
Data::String(DataLayout::Spectrum(arr.iter()
.map(|s| s.to_string_lossy())
.collect::<Vec<_>>()
.into()))
}
_ => return None,
}
}
orb::CORBA_TypeCodeKind::Struct => {
let svalue;
let data0 = if let Some(multi) = self.any.extract_borrow::<orb::Tango_DevVarLongStringArray>() {
svalue = &multi.svalue;
Data::Long(DataLayout::SpectrumView(MdView::from(&multi.lvalue[..])))
} else if let Some(multi) = self.any.extract_borrow::<orb::Tango_DevVarDoubleStringArray>() {
svalue = &multi.svalue;
Data::Double(DataLayout::SpectrumView(MdView::from(&multi.dvalue[..])))
} else {
return None;
};
let data1 = Data::String(DataLayout::Spectrum(svalue.iter()
.map(|s| s.to_string_lossy())
.collect::<Vec<_>>()
.into()));
Data::Struct(DataStruct::Owned(Box::new([data0, data1])))
}
_ => return None,
};
Some(data)
}
}
impl DevCommandBackend for DevCommandFromAny {
fn get(&self) -> Result<Data<'_>> {
self.get_inner().ok_or_else(|| Error::new(ErrorKind::InvalidData)
.with_append_description("Internal CORBA::Any is not supported")
.with_append_description(format_args!("{:?}", self.any)))
}
}
#[derive(Debug)]
pub struct DevGetCommandInfoMany<R> {
raw_list: orb::CppBox<R>,
mapping: Option<Vec<Option<usize>>>,
}
pub trait DevGetCommandInfoBackendExt: DevGetCommandInfoBackend {
fn init_mapping(&mut self, names: &[&str]);
}
impl<R> DevGetCommandInfoMany<R> {
#[inline]
pub fn new(raw_list: orb::CppBox<R>) -> Self {
Self {
raw_list,
mapping: None,
}
}
}
impl DevGetCommandInfoBackend for DevGetCommandInfoMany<orb::Tango_DevCmdInfoList> {
fn len(&self) -> usize {
self.mapping.as_ref()
.map(|mapping| mapping.len())
.unwrap_or(self.raw_list.len())
}
fn get(&self, index: usize) -> Result<CommandInfo<'_>> {
let index = match &self.mapping {
Some(mapping) => mapping.get(index)
.ok_or_else(|| Error::new(ErrorKind::InvalidIndex))?
.ok_or_else(|| Error::new(ErrorKind::CommandNotFound))?,
None if index < self.raw_list.len() => index,
None => return Err(Error::new(ErrorKind::InvalidIndex)),
};
command_info_from_v1(&self.raw_list[index])
}
}
impl DevGetCommandInfoBackendExt for DevGetCommandInfoMany<orb::Tango_DevCmdInfoList> {
fn init_mapping(&mut self, names: &[&str]) {
self.mapping = Some(names.iter()
.map(|&name| self.raw_list.iter().position(|info| info.cmd_name.to_bytes() == name.as_bytes()))
.collect())
}
}
impl DevGetCommandInfoBackend for DevGetCommandInfoMany<orb::Tango_DevCmdInfoList_2> {
fn len(&self) -> usize {
self.mapping.as_ref()
.map(|mapping| mapping.len())
.unwrap_or(self.raw_list.len())
}
fn get(&self, index: usize) -> Result<CommandInfo<'_>> {
let index = match &self.mapping {
Some(mapping) => mapping.get(index)
.ok_or_else(|| Error::new(ErrorKind::InvalidIndex))?
.ok_or_else(|| Error::new(ErrorKind::CommandNotFound))?,
None if index < self.raw_list.len() => index,
None => return Err(Error::new(ErrorKind::InvalidIndex)),
};
command_info_from_v2(&self.raw_list[index])
}
}
impl DevGetCommandInfoBackendExt for DevGetCommandInfoMany<orb::Tango_DevCmdInfoList_2> {
fn init_mapping(&mut self, names: &[&str]) {
self.mapping = Some(names.iter()
.map(|&name| self.raw_list.iter().position(|info| info.cmd_name.to_bytes() == name.as_bytes()))
.collect())
}
}
#[derive(Debug)]
pub struct DevGetCommandInfoSingle<R> {
raw_info: orb::CppBox<R>,
}
impl<R> DevGetCommandInfoSingle<R> {
#[inline]
pub fn new(raw_info: orb::CppBox<R>) -> Self {
Self {
raw_info,
}
}
}
impl DevGetCommandInfoBackend for DevGetCommandInfoSingle<orb::Tango_DevCmdInfo> {
fn len(&self) -> usize {
1
}
fn get(&self, index: usize) -> Result<CommandInfo<'_>> {
if index == 0 {
command_info_from_v1(&self.raw_info)
} else {
Err(Error::new(ErrorKind::InvalidIndex))
}
}
}
impl DevGetCommandInfoBackend for DevGetCommandInfoSingle<orb::Tango_DevCmdInfo_2> {
fn len(&self) -> usize {
1
}
fn get(&self, index: usize) -> Result<CommandInfo<'_>> {
if index == 0 {
command_info_from_v2(&self.raw_info)
} else {
Err(Error::new(ErrorKind::InvalidIndex))
}
}
}
pub fn command_info_from_v1(raw_conf: &orb::Tango_DevCmdInfo) -> Result<CommandInfo<'_>> {
Ok(CommandInfo {
name: raw_conf.cmd_name.to_string_lossy(),
display_level: match raw_conf.cmd_tag {
0 => DisplayLevel::Operator,
1 => DisplayLevel::Expert,
_ => return Err(Error::new(ErrorKind::InvalidData)
.with_append_description(format_args!("Invalid command tag: {:02X}", raw_conf.cmd_tag)))
},
in_kind: data_kind_from_type(raw_conf.in_type, None, None)
.ok_or_else(|| Error::new(ErrorKind::InvalidData)
.with_append_description(format_args!("Unexpected raw tango data type for input: {}", raw_conf.in_type)))?,
out_kind: data_kind_from_type(raw_conf.in_type, None, None)
.ok_or_else(|| Error::new(ErrorKind::InvalidData)
.with_append_description(format_args!("Unexpected raw tango data type for output: {}", raw_conf.in_type)))?,
in_description: opt_str_if(&raw_conf.in_type_desc, S_UNINITIALIZED),
out_description: opt_str_if(&raw_conf.out_type_desc, S_UNINITIALIZED),
})
}
pub fn command_info_from_v2(raw_conf: &orb::Tango_DevCmdInfo_2) -> Result<CommandInfo<'_>> {
Ok(CommandInfo {
name: raw_conf.cmd_name.to_string_lossy(),
display_level: raw_conf.level.into(),
in_kind: data_kind_from_type(raw_conf.in_type, None, None)
.ok_or_else(|| Error::new(ErrorKind::InvalidData)
.with_append_description(format_args!("Unexpected raw tango data type for input: {}", raw_conf.in_type)))?,
out_kind: data_kind_from_type(raw_conf.out_type, None, None)
.ok_or_else(|| Error::new(ErrorKind::InvalidData)
.with_append_description(format_args!("Unexpected raw tango data type for output: {}", raw_conf.in_type)))?,
in_description: opt_str_if(&raw_conf.in_type_desc, S_UNINITIALIZED),
out_description: opt_str_if(&raw_conf.out_type_desc, S_UNINITIALIZED),
})
}