use crate::protocol::dds::byte_cursor::{ByteCursor, ByteWriter};
use crate::protocol::dds::error::RtpsError;
use crate::protocol::dds::types::time::Duration;
const DURATION_INFINITE: Duration = Duration {
seconds: 0x7FFF_FFFF,
fraction: 0xFFFF_FFFF,
};
const FRACTION_100MS: u32 = 0x1999_9999;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReliabilityKind {
BestEffort = 1,
Reliable = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ReliabilityQosPolicy {
pub kind: ReliabilityKind,
pub max_blocking_time: Duration,
}
impl ReliabilityQosPolicy {
pub fn is_compatible_with(&self, writer: &Self) -> bool {
(self.kind as i32) <= (writer.kind as i32)
}
pub fn reliable() -> Self {
Self {
kind: ReliabilityKind::Reliable,
max_blocking_time: Duration {
seconds: 0,
fraction: FRACTION_100MS,
},
}
}
pub fn best_effort() -> Self {
Self {
kind: ReliabilityKind::BestEffort,
max_blocking_time: Duration::zero(),
}
}
pub fn parse(cur: &mut ByteCursor<'_>) -> Result<Self, RtpsError> {
let kind_raw = cur.read_i32()?;
let max_blocking_time = Duration::parse(cur)?;
let kind = match kind_raw {
2 => ReliabilityKind::Reliable,
_ => ReliabilityKind::BestEffort, };
Ok(Self {
kind,
max_blocking_time,
})
}
pub fn serialize(&self, w: &mut ByteWriter<'_>) -> Result<(), RtpsError> {
w.write_i32(self.kind as i32)?;
self.max_blocking_time.serialize(w)
}
}
impl Default for ReliabilityQosPolicy {
fn default() -> Self {
Self::reliable()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HistoryKind {
KeepLast = 0,
KeepAll = 1,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HistoryQosPolicy {
pub kind: HistoryKind,
pub depth: i32,
}
impl HistoryQosPolicy {
pub fn keep_last_1() -> Self {
Self {
kind: HistoryKind::KeepLast,
depth: 1,
}
}
pub fn parse(cur: &mut ByteCursor<'_>) -> Result<Self, RtpsError> {
let kind_raw = cur.read_i32()?;
let depth = cur.read_i32()?;
let kind = match kind_raw {
1 => HistoryKind::KeepAll,
_ => HistoryKind::KeepLast,
};
Ok(Self { kind, depth })
}
pub fn serialize(&self, w: &mut ByteWriter<'_>) -> Result<(), RtpsError> {
w.write_i32(self.kind as i32)?;
w.write_i32(self.depth)
}
}
impl Default for HistoryQosPolicy {
fn default() -> Self {
Self::keep_last_1()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DurabilityKind {
Volatile = 0,
TransientLocal = 1,
Transient = 2,
Persistent = 3,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DurabilityQosPolicy {
pub kind: DurabilityKind,
}
impl DurabilityQosPolicy {
pub fn is_compatible_with(&self, writer: &Self) -> bool {
(self.kind as i32) <= (writer.kind as i32)
}
pub fn volatile() -> Self {
Self {
kind: DurabilityKind::Volatile,
}
}
pub fn parse(cur: &mut ByteCursor<'_>) -> Result<Self, RtpsError> {
let kind_raw = cur.read_i32()?;
let kind = match kind_raw {
1 => DurabilityKind::TransientLocal,
2 => DurabilityKind::Transient,
3 => DurabilityKind::Persistent,
_ => DurabilityKind::Volatile,
};
Ok(Self { kind })
}
pub fn serialize(&self, w: &mut ByteWriter<'_>) -> Result<(), RtpsError> {
w.write_i32(self.kind as i32)
}
}
impl Default for DurabilityQosPolicy {
fn default() -> Self {
Self::volatile()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LivelinessKind {
Automatic = 0,
ManualByParticipant = 1,
ManualByTopic = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LivelinessQosPolicy {
pub kind: LivelinessKind,
pub lease_duration: Duration,
}
impl LivelinessQosPolicy {
pub fn is_compatible_with(&self, writer: &Self) -> bool {
if (self.kind as i32) > (writer.kind as i32) {
return false;
}
cmp_duration(self.lease_duration, writer.lease_duration) != core::cmp::Ordering::Less
}
pub fn automatic_infinite() -> Self {
Self {
kind: LivelinessKind::Automatic,
lease_duration: DURATION_INFINITE,
}
}
pub fn parse(cur: &mut ByteCursor<'_>) -> Result<Self, RtpsError> {
let kind_raw = cur.read_i32()?;
let lease_duration = Duration::parse(cur)?;
let kind = match kind_raw {
1 => LivelinessKind::ManualByParticipant,
2 => LivelinessKind::ManualByTopic,
_ => LivelinessKind::Automatic,
};
Ok(Self {
kind,
lease_duration,
})
}
pub fn serialize(&self, w: &mut ByteWriter<'_>) -> Result<(), RtpsError> {
w.write_i32(self.kind as i32)?;
self.lease_duration.serialize(w)
}
}
impl Default for LivelinessQosPolicy {
fn default() -> Self {
Self::automatic_infinite()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DeadlineQosPolicy {
pub period: Duration,
}
impl DeadlineQosPolicy {
pub fn is_compatible_with(&self, writer: &Self) -> bool {
cmp_duration(self.period, writer.period) != core::cmp::Ordering::Less
}
pub fn infinite() -> Self {
Self {
period: DURATION_INFINITE,
}
}
pub fn parse(cur: &mut ByteCursor<'_>) -> Result<Self, RtpsError> {
let period = Duration::parse(cur)?;
Ok(Self { period })
}
pub fn serialize(&self, w: &mut ByteWriter<'_>) -> Result<(), RtpsError> {
self.period.serialize(w)
}
}
impl Default for DeadlineQosPolicy {
fn default() -> Self {
Self::infinite()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LifespanQosPolicy {
pub duration: Duration,
}
impl LifespanQosPolicy {
pub fn infinite() -> Self {
Self {
duration: DURATION_INFINITE,
}
}
pub fn parse(cur: &mut ByteCursor<'_>) -> Result<Self, RtpsError> {
let duration = Duration::parse(cur)?;
Ok(Self { duration })
}
pub fn serialize(&self, w: &mut ByteWriter<'_>) -> Result<(), RtpsError> {
self.duration.serialize(w)
}
}
impl Default for LifespanQosPolicy {
fn default() -> Self {
Self::infinite()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OwnershipKind {
Shared = 0,
Exclusive = 1,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OwnershipQosPolicy {
pub kind: OwnershipKind,
}
impl OwnershipQosPolicy {
pub fn shared() -> Self {
Self {
kind: OwnershipKind::Shared,
}
}
pub fn exclusive() -> Self {
Self {
kind: OwnershipKind::Exclusive,
}
}
pub fn is_compatible_with(&self, writer: &Self) -> bool {
self.kind == writer.kind
}
pub fn parse(cur: &mut ByteCursor<'_>) -> Result<Self, RtpsError> {
let kind_raw = cur.read_i32()?;
let kind = match kind_raw {
1 => OwnershipKind::Exclusive,
_ => OwnershipKind::Shared,
};
Ok(Self { kind })
}
pub fn serialize(&self, w: &mut ByteWriter<'_>) -> Result<(), RtpsError> {
w.write_i32(self.kind as i32)
}
}
impl Default for OwnershipQosPolicy {
fn default() -> Self {
Self::shared()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct OwnershipStrengthQosPolicy {
pub value: i32,
}
impl OwnershipStrengthQosPolicy {
pub fn new(value: i32) -> Self {
Self { value }
}
pub fn parse(cur: &mut ByteCursor<'_>) -> Result<Self, RtpsError> {
let value = cur.read_i32()?;
Ok(Self { value })
}
pub fn serialize(&self, w: &mut ByteWriter<'_>) -> Result<(), RtpsError> {
w.write_i32(self.value)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DestinationOrderKind {
ByReceptionTimestamp = 0,
BySourceTimestamp = 1,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DestinationOrderQosPolicy {
pub kind: DestinationOrderKind,
}
impl DestinationOrderQosPolicy {
pub fn by_reception_timestamp() -> Self {
Self {
kind: DestinationOrderKind::ByReceptionTimestamp,
}
}
pub fn by_source_timestamp() -> Self {
Self {
kind: DestinationOrderKind::BySourceTimestamp,
}
}
pub fn is_compatible_with(&self, writer: &Self) -> bool {
(self.kind as i32) <= (writer.kind as i32)
}
pub fn parse(cur: &mut ByteCursor<'_>) -> Result<Self, RtpsError> {
let kind_raw = cur.read_i32()?;
let kind = match kind_raw {
1 => DestinationOrderKind::BySourceTimestamp,
_ => DestinationOrderKind::ByReceptionTimestamp,
};
Ok(Self { kind })
}
pub fn serialize(&self, w: &mut ByteWriter<'_>) -> Result<(), RtpsError> {
w.write_i32(self.kind as i32)
}
}
impl Default for DestinationOrderQosPolicy {
fn default() -> Self {
Self::by_reception_timestamp()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ResourceLimitsQosPolicy {
pub max_samples: i32,
pub max_instances: i32,
pub max_samples_per_instance: i32,
}
impl ResourceLimitsQosPolicy {
pub fn unlimited() -> Self {
Self {
max_samples: -1,
max_instances: -1,
max_samples_per_instance: -1,
}
}
pub fn parse(cur: &mut ByteCursor<'_>) -> Result<Self, RtpsError> {
let max_samples = cur.read_i32()?;
let max_instances = cur.read_i32()?;
let max_samples_per_instance = cur.read_i32()?;
Ok(Self {
max_samples,
max_instances,
max_samples_per_instance,
})
}
pub fn serialize(&self, w: &mut ByteWriter<'_>) -> Result<(), RtpsError> {
w.write_i32(self.max_samples)?;
w.write_i32(self.max_instances)?;
w.write_i32(self.max_samples_per_instance)
}
}
impl Default for ResourceLimitsQosPolicy {
fn default() -> Self {
Self::unlimited()
}
}
pub(crate) fn cmp_duration(a: Duration, b: Duration) -> core::cmp::Ordering {
const INF_S: i32 = 0x7FFF_FFFF;
const INF_F: u32 = 0xFFFF_FFFF;
let a_inf = a.seconds == INF_S && a.fraction == INF_F;
let b_inf = b.seconds == INF_S && b.fraction == INF_F;
match (a_inf, b_inf) {
(true, true) => core::cmp::Ordering::Equal,
(true, false) => core::cmp::Ordering::Greater,
(false, true) => core::cmp::Ordering::Less,
(false, false) => {
let sc = a.seconds.cmp(&b.seconds);
if sc != core::cmp::Ordering::Equal {
sc
} else {
a.fraction.cmp(&b.fraction)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const INFINITE: Duration = Duration {
seconds: 0x7FFF_FFFF,
fraction: 0xFFFF_FFFF,
};
fn dur(seconds: i32, fraction: u32) -> Duration {
Duration { seconds, fraction }
}
#[test]
fn cmp_duration_both_infinite_equal() {
assert_eq!(cmp_duration(INFINITE, INFINITE), core::cmp::Ordering::Equal);
}
#[test]
fn cmp_duration_inf_greater_than_finite() {
assert_eq!(
cmp_duration(INFINITE, dur(1, 0)),
core::cmp::Ordering::Greater
);
}
#[test]
fn cmp_duration_finite_less_than_inf() {
assert_eq!(cmp_duration(dur(1, 0), INFINITE), core::cmp::Ordering::Less);
}
#[test]
fn cmp_duration_seconds_dominate() {
assert_eq!(
cmp_duration(dur(2, 0), dur(1, 0xFFFF_FFFE)),
core::cmp::Ordering::Greater
);
}
#[test]
fn cmp_duration_equal_seconds_fraction_breaks_tie() {
assert_eq!(
cmp_duration(dur(1, 500), dur(1, 200)),
core::cmp::Ordering::Greater
);
assert_eq!(
cmp_duration(dur(1, 200), dur(1, 500)),
core::cmp::Ordering::Less
);
}
#[test]
fn cmp_duration_zero_less_than_one_sec() {
assert_eq!(
cmp_duration(dur(0, 0), dur(1, 0)),
core::cmp::Ordering::Less
);
}
fn le_cursor(bytes: &[u8]) -> ByteCursor<'_> {
use crate::protocol::dds::byte_cursor::Endianness;
ByteCursor::new(bytes, Endianness::Little)
}
fn le_writer(buf: &mut [u8]) -> ByteWriter<'_> {
use crate::protocol::dds::byte_cursor::Endianness;
ByteWriter::new(buf, Endianness::Little)
}
#[test]
fn lifespan_default_is_infinite() {
let p = LifespanQosPolicy::default();
assert_eq!(p.duration.seconds, 0x7FFF_FFFF);
assert_eq!(p.duration.fraction, 0xFFFF_FFFF);
}
#[test]
fn lifespan_serialize_parse_roundtrip() {
let original = LifespanQosPolicy {
duration: dur(5, 0),
};
let mut buf = [0u8; 8];
original
.serialize(&mut le_writer(&mut buf))
.expect("serialize");
let parsed = LifespanQosPolicy::parse(&mut le_cursor(&buf)).expect("parse");
assert_eq!(original, parsed);
}
#[test]
fn lifespan_serialize_parse_zero_duration() {
let original = LifespanQosPolicy {
duration: dur(0, 0),
};
let mut buf = [0u8; 8];
original
.serialize(&mut le_writer(&mut buf))
.expect("serialize");
let parsed = LifespanQosPolicy::parse(&mut le_cursor(&buf)).expect("parse");
assert_eq!(original, parsed);
assert_eq!(parsed.duration.seconds, 0);
assert_eq!(parsed.duration.fraction, 0);
}
#[test]
fn ownership_shared_default() {
let p = OwnershipQosPolicy::default();
assert_eq!(p.kind, OwnershipKind::Shared);
}
#[test]
fn ownership_serialize_parse_shared() {
let original = OwnershipQosPolicy::shared();
let mut buf = [0u8; 4];
original
.serialize(&mut le_writer(&mut buf))
.expect("serialize");
let parsed = OwnershipQosPolicy::parse(&mut le_cursor(&buf)).expect("parse");
assert_eq!(parsed.kind, OwnershipKind::Shared);
}
#[test]
fn ownership_serialize_parse_exclusive() {
let original = OwnershipQosPolicy::exclusive();
let mut buf = [0u8; 4];
original
.serialize(&mut le_writer(&mut buf))
.expect("serialize");
let parsed = OwnershipQosPolicy::parse(&mut le_cursor(&buf)).expect("parse");
assert_eq!(parsed.kind, OwnershipKind::Exclusive);
}
#[test]
fn ownership_compatible_both_shared() {
let reader = OwnershipQosPolicy::shared();
let writer = OwnershipQosPolicy::shared();
assert!(reader.is_compatible_with(&writer));
}
#[test]
fn ownership_incompatible_shared_vs_exclusive() {
let reader = OwnershipQosPolicy::shared();
let writer = OwnershipQosPolicy::exclusive();
assert!(!reader.is_compatible_with(&writer));
}
#[test]
fn ownership_incompatible_exclusive_vs_shared() {
let reader = OwnershipQosPolicy::exclusive();
let writer = OwnershipQosPolicy::shared();
assert!(!reader.is_compatible_with(&writer));
}
#[test]
fn ownership_strength_default_zero() {
let p = OwnershipStrengthQosPolicy::default();
assert_eq!(p.value, 0);
}
#[test]
fn ownership_strength_serialize_parse() {
let original = OwnershipStrengthQosPolicy::new(42);
let mut buf = [0u8; 4];
original
.serialize(&mut le_writer(&mut buf))
.expect("serialize");
let parsed = OwnershipStrengthQosPolicy::parse(&mut le_cursor(&buf)).expect("parse");
assert_eq!(parsed.value, 42);
}
#[test]
fn destination_order_default_by_reception_timestamp() {
let p = DestinationOrderQosPolicy::default();
assert_eq!(p.kind, DestinationOrderKind::ByReceptionTimestamp);
}
#[test]
fn destination_order_serialize_parse_by_source() {
let original = DestinationOrderQosPolicy::by_source_timestamp();
let mut buf = [0u8; 4];
original
.serialize(&mut le_writer(&mut buf))
.expect("serialize");
let parsed = DestinationOrderQosPolicy::parse(&mut le_cursor(&buf)).expect("parse");
assert_eq!(parsed.kind, DestinationOrderKind::BySourceTimestamp);
}
#[test]
fn destination_order_compatible_by_reception_reader_by_source_writer() {
let reader = DestinationOrderQosPolicy::by_reception_timestamp();
let writer = DestinationOrderQosPolicy::by_source_timestamp();
assert!(reader.is_compatible_with(&writer));
}
#[test]
fn destination_order_incompatible_by_source_reader_by_reception_writer() {
let reader = DestinationOrderQosPolicy::by_source_timestamp();
let writer = DestinationOrderQosPolicy::by_reception_timestamp();
assert!(!reader.is_compatible_with(&writer));
}
#[test]
fn resource_limits_unlimited_default() {
let p = ResourceLimitsQosPolicy::default();
assert_eq!(p.max_samples, -1);
assert_eq!(p.max_instances, -1);
assert_eq!(p.max_samples_per_instance, -1);
}
#[test]
fn resource_limits_serialize_parse_finite() {
let original = ResourceLimitsQosPolicy {
max_samples: 100,
max_instances: 10,
max_samples_per_instance: 5,
};
let mut buf = [0u8; 12];
original
.serialize(&mut le_writer(&mut buf))
.expect("serialize");
let parsed = ResourceLimitsQosPolicy::parse(&mut le_cursor(&buf)).expect("parse");
assert_eq!(parsed.max_samples, 100);
assert_eq!(parsed.max_instances, 10);
assert_eq!(parsed.max_samples_per_instance, 5);
}
}