extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ObjectReference {
pub type_id: String,
pub iiop_profile: Vec<u8>,
}
const TAG_INTERNET_IOP: u32 = 0;
impl zerodds_cdr::CdrEncode for ObjectReference {
fn encode(
&self,
writer: &mut zerodds_cdr::BufferWriter,
) -> ::core::result::Result<(), zerodds_cdr::EncodeError> {
writer.write_string(&self.type_id)?;
writer.write_u32(1)?; writer.write_u32(TAG_INTERNET_IOP)?;
writer.write_u32(self.iiop_profile.len() as u32)?;
writer.write_bytes(&self.iiop_profile)?;
::core::result::Result::Ok(())
}
}
impl zerodds_cdr::CdrDecode for ObjectReference {
fn decode(
reader: &mut zerodds_cdr::BufferReader<'_>,
) -> ::core::result::Result<Self, zerodds_cdr::DecodeError> {
let type_id = reader.read_string()?;
let profile_count = reader.read_u32()?;
let mut iiop_profile = Vec::new();
for _ in 0..profile_count {
let tag = reader.read_u32()?;
let len = reader.read_u32()? as usize;
let data = reader.read_bytes(len)?;
if tag == TAG_INTERNET_IOP && iiop_profile.is_empty() {
iiop_profile = data.to_vec();
}
}
::core::result::Result::Ok(Self {
type_id,
iiop_profile,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum CorbaException {
SystemException {
minor: u32,
message: &'static str,
},
UserException {
repository_id: String,
body: Vec<u8>,
endianness: zerodds_cdr::Endianness,
},
}
impl ::core::fmt::Display for CorbaException {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
match self {
Self::SystemException { minor, message } => {
write!(f, "CORBA::SystemException(minor={minor}): {message}")
}
Self::UserException { repository_id, .. } => {
write!(f, "CORBA::UserException({repository_id})")
}
}
}
}
impl ::std::error::Error for CorbaException {}
pub trait ValueBase {
fn repository_id(&self) -> &str;
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum SkeletonResult {
Reply(Vec<u8>),
Exception(CorbaException),
BadOperation,
NotYetWired,
}
pub trait Servant {
fn target_repository_id(&self) -> &str;
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct TypeCode {
pub repository_id: String,
}
impl TypeCode {
#[must_use]
pub fn new(repository_id: impl Into<String>) -> Self {
Self {
repository_id: repository_id.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PoaBuilder {
pub thread_policy: ThreadPolicy,
pub lifespan_policy: LifespanPolicy,
pub id_assignment_policy: IdAssignmentPolicy,
pub id_uniqueness_policy: IdUniquenessPolicy,
pub implicit_activation_policy: ImplicitActivationPolicy,
pub servant_retention_policy: ServantRetentionPolicy,
pub request_processing_policy: RequestProcessingPolicy,
}
impl Default for PoaBuilder {
fn default() -> Self {
Self::new()
}
}
impl PoaBuilder {
#[must_use]
pub fn new() -> Self {
Self {
thread_policy: ThreadPolicy::OrbCtrlModel,
lifespan_policy: LifespanPolicy::Transient,
id_assignment_policy: IdAssignmentPolicy::SystemId,
id_uniqueness_policy: IdUniquenessPolicy::Unique,
implicit_activation_policy: ImplicitActivationPolicy::NoImplicitActivation,
servant_retention_policy: ServantRetentionPolicy::Retain,
request_processing_policy: RequestProcessingPolicy::UseActiveObjectMapOnly,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ThreadPolicy {
OrbCtrlModel,
SingleThreadModel,
MainThreadModel,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LifespanPolicy {
Transient,
Persistent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IdAssignmentPolicy {
SystemId,
UserId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IdUniquenessPolicy {
Unique,
Multiple,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ImplicitActivationPolicy {
NoImplicitActivation,
ImplicitActivation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServantRetentionPolicy {
Retain,
NonRetain,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RequestProcessingPolicy {
UseActiveObjectMapOnly,
UseDefaultServant,
UseServantManager,
}
pub struct ValueStreamWriter<'a> {
pub inner: &'a mut zerodds_cdr::BufferWriter,
}
impl<'a> ValueStreamWriter<'a> {
pub fn new(inner: &'a mut zerodds_cdr::BufferWriter) -> Self {
Self { inner }
}
pub fn write_value_tag(
&mut self,
repository_id: &str,
) -> ::core::result::Result<(), zerodds_cdr::EncodeError> {
self.inner.write_u32(0x7FFF_FF02)?;
self.inner.write_string(repository_id)?;
Ok(())
}
pub fn write_value_tag_multi(
&mut self,
repository_ids: &[&str],
) -> ::core::result::Result<(), zerodds_cdr::EncodeError> {
debug_assert!(
!repository_ids.is_empty(),
"Spec §15.3.4.2: list-of-repository-ids must contain >=1 entry"
);
self.inner.write_u32(0x7FFF_FF06)?;
let count: i32 = repository_ids.len() as i32;
self.inner.write_u32(count as u32)?;
for id in repository_ids {
self.inner.write_string(id)?;
}
Ok(())
}
pub fn write_chunked_value_tag(
&mut self,
repository_ids: &[&str],
) -> ::core::result::Result<(), zerodds_cdr::EncodeError> {
debug_assert!(
!repository_ids.is_empty(),
"Spec §15.3.4.2: list-of-repository-ids must contain >=1 entry"
);
self.inner.write_u32(0x7FFF_FF0A)?;
let count: i32 = repository_ids.len() as i32;
self.inner.write_u32(count as u32)?;
for id in repository_ids {
self.inner.write_string(id)?;
}
Ok(())
}
pub fn write_chunk(
&mut self,
chunk_data: &[u8],
) -> ::core::result::Result<(), zerodds_cdr::EncodeError> {
let size: i32 = chunk_data.len() as i32;
self.inner.write_u32(size as u32)?;
for b in chunk_data {
self.inner.write_u8(*b)?;
}
Ok(())
}
pub fn write_chunked_end(
&mut self,
nesting_level: u32,
) -> ::core::result::Result<(), zerodds_cdr::EncodeError> {
debug_assert!(
nesting_level >= 1,
"Spec §15.3.4.3: chunked-end nesting_level must be >= 1"
);
let end_tag: i32 = -(nesting_level as i32);
self.inner.write_u32(end_tag as u32)?;
Ok(())
}
}
pub struct ValueStreamReader<'a, 'b> {
pub inner: &'a mut zerodds_cdr::BufferReader<'b>,
}
impl<'a, 'b> ValueStreamReader<'a, 'b> {
pub fn new(inner: &'a mut zerodds_cdr::BufferReader<'b>) -> Self {
Self { inner }
}
pub fn read_value_tag(
&mut self,
) -> ::core::result::Result<Option<String>, zerodds_cdr::DecodeError> {
let header = self.read_value_tag_full()?;
Ok(match header {
ValueTagHeader::Null => None,
ValueTagHeader::Single(id) => Some(id),
ValueTagHeader::List(ids) => ids.into_iter().next(),
ValueTagHeader::ChunkedList(ids) => ids.into_iter().next(),
})
}
pub fn read_value_tag_full(
&mut self,
) -> ::core::result::Result<ValueTagHeader, zerodds_cdr::DecodeError> {
let tag = self.inner.read_u32()?;
match tag {
0x0000_0000 => Ok(ValueTagHeader::Null),
0x7FFF_FF02 => {
let id = self.inner.read_string()?;
Ok(ValueTagHeader::Single(id))
}
0x7FFF_FF06 => {
let count = self.inner.read_u32()? as usize;
let mut ids = Vec::with_capacity(count);
for _ in 0..count {
ids.push(self.inner.read_string()?);
}
Ok(ValueTagHeader::List(ids))
}
0x7FFF_FF0A => {
let count = self.inner.read_u32()? as usize;
let mut ids = Vec::with_capacity(count);
for _ in 0..count {
ids.push(self.inner.read_string()?);
}
Ok(ValueTagHeader::ChunkedList(ids))
}
_ => Err(zerodds_cdr::DecodeError::InvalidString {
offset: 0,
reason: "ValueStream: unsupported value-tag (only 0/0x7FFFFF02/0x7FFFFF06/0x7FFFFF0A)",
}),
}
}
pub fn read_chunk_size(&mut self) -> ::core::result::Result<i32, zerodds_cdr::DecodeError> {
let raw = self.inner.read_u32()?;
Ok(raw as i32)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ValueTagHeader {
Null,
Single(String),
List(Vec<String>),
ChunkedList(Vec<String>),
}
pub trait ComponentServant: Servant {
fn component_repository_id(&self) -> &str;
}
pub trait ComponentHome {
fn home_repository_id(&self) -> &str;
}
pub trait CorbaConnection {
fn invoke(
&self,
target_ior: &ObjectReference,
operation: &str,
request_endianness: zerodds_cdr::Endianness,
request_payload: &[u8],
) -> Result<(Vec<u8>, zerodds_cdr::Endianness), CorbaException>;
fn invoke_oneway(
&self,
target_ior: &ObjectReference,
operation: &str,
request_endianness: zerodds_cdr::Endianness,
request_payload: &[u8],
) -> Result<(), CorbaException>;
}
pub type AsyncReply = Result<(Vec<u8>, zerodds_cdr::Endianness), CorbaException>;
pub type AsyncReplyCallback = alloc::boxed::Box<dyn FnOnce(AsyncReply) + Send>;
pub trait AsyncCorbaChannel {
fn send(
&mut self,
operation: &str,
payload: &[u8],
cb: AsyncReplyCallback,
) -> Result<u32, CorbaException>;
fn send_poll(&mut self, operation: &str, payload: &[u8]) -> Result<u32, CorbaException>;
fn get_reply(&mut self, request_id: u32) -> Result<AsyncReply, CorbaException>;
fn perform_work(&mut self) -> Result<u32, CorbaException>;
fn perform_all(&mut self) -> Result<(), CorbaException>;
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
mod object_reference_tests {
use super::*;
use zerodds_cdr::{BufferReader, BufferWriter, CdrDecode, CdrEncode, Endianness};
#[test]
fn object_reference_roundtrips_as_ior() {
let obj = ObjectReference {
type_id: "IDL:demo/Bench:1.0".into(),
iiop_profile: alloc::vec![0x01, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef],
};
let mut w = BufferWriter::new(Endianness::Big);
obj.encode(&mut w).unwrap();
let bytes = w.into_bytes();
let mut r = BufferReader::new(&bytes, Endianness::Big);
assert_eq!(r.read_string().unwrap(), "IDL:demo/Bench:1.0");
assert_eq!(r.read_u32().unwrap(), 1, "exactly one profile");
assert_eq!(r.read_u32().unwrap(), 0, "TAG_INTERNET_IOP");
assert_eq!(r.read_u32().unwrap(), 8, "profile_data length");
let mut r2 = BufferReader::new(&bytes, Endianness::Big);
let decoded = ObjectReference::decode(&mut r2).unwrap();
assert_eq!(decoded, obj);
}
#[test]
fn object_reference_little_endian_roundtrips() {
let obj = ObjectReference {
type_id: "IDL:X:1.0".into(),
iiop_profile: alloc::vec![1, 2, 3],
};
let mut w = BufferWriter::new(Endianness::Little);
obj.encode(&mut w).unwrap();
let bytes = w.into_bytes();
let mut r = BufferReader::new(&bytes, Endianness::Little);
assert_eq!(ObjectReference::decode(&mut r).unwrap(), obj);
}
}