use crate::error::WireError;
pub mod attrs {
pub const IS_VALID: u32 = 0x8000_0000;
pub const IS_RTPS_PROTECTED: u32 = 0x0000_0001;
pub const IS_DISCOVERY_PROTECTED: u32 = 0x0000_0002;
pub const IS_LIVELINESS_PROTECTED: u32 = 0x0000_0004;
}
pub mod plugin_attrs {
pub const IS_VALID: u32 = 0x8000_0000;
pub const IS_RTPS_ENCRYPTED: u32 = 0x0000_0001;
pub const IS_DISCOVERY_ENCRYPTED: u32 = 0x0000_0002;
pub const IS_LIVELINESS_ENCRYPTED: u32 = 0x0000_0004;
pub const IS_RTPS_ORIGIN_AUTHENTICATED: u32 = 0x0000_0008;
pub const IS_DISCOVERY_ORIGIN_AUTHENTICATED: u32 = 0x0000_0010;
pub const IS_LIVELINESS_ORIGIN_AUTHENTICATED: u32 = 0x0000_0020;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct ParticipantSecurityInfo {
pub participant_security_attributes: u32,
pub plugin_participant_security_attributes: u32,
}
impl ParticipantSecurityInfo {
pub const WIRE_SIZE: usize = 8;
#[must_use]
pub fn to_le_bytes(&self) -> [u8; 8] {
let mut out = [0u8; 8];
out[0..4].copy_from_slice(&self.participant_security_attributes.to_le_bytes());
out[4..8].copy_from_slice(&self.plugin_participant_security_attributes.to_le_bytes());
out
}
pub fn from_le_bytes(bytes: &[u8]) -> Result<Self, WireError> {
if bytes.len() < Self::WIRE_SIZE {
return Err(WireError::UnexpectedEof {
needed: Self::WIRE_SIZE - bytes.len(),
offset: 0,
});
}
let mut a = [0u8; 4];
a.copy_from_slice(&bytes[0..4]);
let mut b = [0u8; 4];
b.copy_from_slice(&bytes[4..8]);
Ok(Self {
participant_security_attributes: u32::from_le_bytes(a),
plugin_participant_security_attributes: u32::from_le_bytes(b),
})
}
#[must_use]
pub fn is_valid(&self) -> bool {
(self.participant_security_attributes & attrs::IS_VALID) != 0
&& (self.plugin_participant_security_attributes & plugin_attrs::IS_VALID) != 0
}
#[must_use]
pub fn fully_protected_default() -> Self {
Self {
participant_security_attributes: attrs::IS_VALID
| attrs::IS_RTPS_PROTECTED
| attrs::IS_DISCOVERY_PROTECTED
| attrs::IS_LIVELINESS_PROTECTED,
plugin_participant_security_attributes: plugin_attrs::IS_VALID
| plugin_attrs::IS_RTPS_ENCRYPTED
| plugin_attrs::IS_DISCOVERY_ENCRYPTED
| plugin_attrs::IS_LIVELINESS_ENCRYPTED,
}
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn round_trip_default() {
let info = ParticipantSecurityInfo::default();
let bytes = info.to_le_bytes();
let back = ParticipantSecurityInfo::from_le_bytes(&bytes).unwrap();
assert_eq!(back, info);
}
#[test]
fn round_trip_fully_protected() {
let info = ParticipantSecurityInfo::fully_protected_default();
let bytes = info.to_le_bytes();
let back = ParticipantSecurityInfo::from_le_bytes(&bytes).unwrap();
assert_eq!(back, info);
assert!(back.is_valid());
}
#[test]
fn is_valid_requires_both_masks() {
let info = ParticipantSecurityInfo {
participant_security_attributes: attrs::IS_VALID,
plugin_participant_security_attributes: 0,
};
assert!(!info.is_valid(), "second mask not valid");
let info = ParticipantSecurityInfo {
participant_security_attributes: 0,
plugin_participant_security_attributes: plugin_attrs::IS_VALID,
};
assert!(!info.is_valid(), "first mask not valid");
}
#[test]
fn short_buffer_rejected() {
assert!(matches!(
ParticipantSecurityInfo::from_le_bytes(&[0; 4]),
Err(WireError::UnexpectedEof { .. })
));
}
#[test]
fn wire_size_is_8() {
assert_eq!(ParticipantSecurityInfo::WIRE_SIZE, 8);
}
#[test]
fn fully_protected_sets_all_protection_bits() {
let info = ParticipantSecurityInfo::fully_protected_default();
assert_ne!(
info.participant_security_attributes & attrs::IS_RTPS_PROTECTED,
0
);
assert_ne!(
info.participant_security_attributes & attrs::IS_DISCOVERY_PROTECTED,
0
);
assert_ne!(
info.participant_security_attributes & attrs::IS_LIVELINESS_PROTECTED,
0
);
}
#[test]
fn fully_protected_sets_all_encrypt_bits() {
let info = ParticipantSecurityInfo::fully_protected_default();
assert_ne!(
info.plugin_participant_security_attributes & plugin_attrs::IS_RTPS_ENCRYPTED,
0
);
assert_ne!(
info.plugin_participant_security_attributes & plugin_attrs::IS_DISCOVERY_ENCRYPTED,
0
);
}
#[test]
fn empty_default_is_not_valid() {
let info = ParticipantSecurityInfo::default();
assert!(!info.is_valid());
}
}