use alloc::format;
use alloc::string::String;
use zerodds_rtps::wire_types::{EntityId, Guid, GuidPrefix};
pub const TYPELOOKUP_TOPIC_PREFIX: &str = "dds.builtin.TOS";
#[must_use]
pub fn format_service_instance_name(prefix: &GuidPrefix) -> String {
let mut hex = String::with_capacity(24);
for b in prefix.0.iter() {
hex.push_str(&format!("{b:02x}"));
}
format!("{TYPELOOKUP_TOPIC_PREFIX}.{hex}")
}
#[must_use]
pub fn format_service_instance_name_short(prefix: &GuidPrefix) -> String {
let mut hex = String::with_capacity(16);
for b in prefix.0[..8].iter() {
hex.push_str(&format!("{b:02x}"));
}
format!("{TYPELOOKUP_TOPIC_PREFIX}.{hex}")
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TypeLookupEndpoints {
pub prefix: GuidPrefix,
}
impl TypeLookupEndpoints {
#[must_use]
pub fn new(prefix: GuidPrefix) -> Self {
Self { prefix }
}
#[must_use]
pub fn request_writer(&self) -> Guid {
Guid::new(self.prefix, EntityId::TL_SVC_REQ_WRITER)
}
#[must_use]
pub fn request_reader(&self) -> Guid {
Guid::new(self.prefix, EntityId::TL_SVC_REQ_READER)
}
#[must_use]
pub fn reply_writer(&self) -> Guid {
Guid::new(self.prefix, EntityId::TL_SVC_REPLY_WRITER)
}
#[must_use]
pub fn reply_reader(&self) -> Guid {
Guid::new(self.prefix, EntityId::TL_SVC_REPLY_READER)
}
#[must_use]
pub fn service_instance_name(&self) -> String {
format_service_instance_name(&self.prefix)
}
#[must_use]
pub fn all_guids(&self) -> [Guid; 4] {
[
self.request_writer(),
self.request_reader(),
self.reply_writer(),
self.reply_reader(),
]
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn service_instance_name_format() {
let prefix = GuidPrefix::from_bytes([
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
]);
let name = format_service_instance_name(&prefix);
assert_eq!(name, "dds.builtin.TOS.0102030405060708090a0b0c");
assert!(name.starts_with(TYPELOOKUP_TOPIC_PREFIX));
}
#[test]
fn service_instance_name_short_takes_first_8_bytes() {
let prefix = GuidPrefix::from_bytes([
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
]);
let name = format_service_instance_name_short(&prefix);
assert_eq!(name, "dds.builtin.TOS.aabbccddeeff0011");
}
#[test]
fn endpoints_have_distinct_entity_ids() {
let e = TypeLookupEndpoints::new(GuidPrefix::from_bytes([0; 12]));
let g = e.all_guids();
for i in 0..g.len() {
for j in (i + 1)..g.len() {
assert_ne!(g[i].entity_id, g[j].entity_id);
}
}
}
#[test]
fn endpoints_share_prefix() {
let prefix = GuidPrefix::from_bytes([0xAA; 12]);
let e = TypeLookupEndpoints::new(prefix);
for g in e.all_guids() {
assert_eq!(g.prefix, prefix);
}
}
#[test]
fn entity_ids_match_spec_constants() {
let e = TypeLookupEndpoints::new(GuidPrefix::from_bytes([1; 12]));
assert_eq!(e.request_writer().entity_id, EntityId::TL_SVC_REQ_WRITER);
assert_eq!(e.request_reader().entity_id, EntityId::TL_SVC_REQ_READER);
assert_eq!(e.reply_writer().entity_id, EntityId::TL_SVC_REPLY_WRITER);
assert_eq!(e.reply_reader().entity_id, EntityId::TL_SVC_REPLY_READER);
}
#[test]
fn service_instance_name_via_endpoints() {
let prefix = GuidPrefix::from_bytes([0x00; 12]);
let e = TypeLookupEndpoints::new(prefix);
assert_eq!(
e.service_instance_name(),
format_service_instance_name(&prefix)
);
}
}