use super::responses::ResponseId;
use std::fmt;
use velo_ext::WorkerId;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct MessageId(ResponseId);
impl MessageId {
pub(crate) fn new(response_id: ResponseId) -> Self {
Self(response_id)
}
#[expect(dead_code)]
pub(crate) fn response_id(&self) -> ResponseId {
self.0
}
pub fn worker_id(&self) -> WorkerId {
WorkerId::from_u64(self.0.worker_id())
}
pub fn worker(&self) -> String {
let worker_id = self.worker_id().as_u64();
Self::encode_u64_base58(worker_id)
}
pub fn message(&self) -> String {
let message_id = self.generation() << 16 | self.slot_index() as u64;
Self::encode_u64_base58(message_id)
}
pub(crate) fn slot_index(&self) -> usize {
self.0.slot_index()
}
pub(crate) fn generation(&self) -> u64 {
self.0.generation()
}
fn encode_u64_base58(value: u64) -> String {
bs58::encode(value.to_be_bytes()).into_string()
}
fn display_parts(&self) -> (String, String) {
(self.worker(), self.message())
}
}
impl From<ResponseId> for MessageId {
fn from(response_id: ResponseId) -> Self {
Self(response_id)
}
}
impl From<MessageId> for ResponseId {
fn from(message_id: MessageId) -> Self {
message_id.0
}
}
impl fmt::Display for MessageId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (worker, message) = self.display_parts();
write!(f, "w:{} / m:{}", worker, message)
}
}
impl fmt::Debug for MessageId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "MessageId({})", self.0)
} else {
f.debug_struct("MessageId")
.field("worker", &format_args!("{:#x}", self.worker_id().as_u64()))
.field("slot", &self.slot_index())
.field("generation", &format_args!("{:#x}", self.generation()))
.finish()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_message_id_display() {
let response_id = ResponseId::from_u128(0x0001_0000_0000_002A_0000_0000_0000_1234);
let msg_id = MessageId::new(response_id);
let display = format!("{}", msg_id);
assert!(display.contains("/"));
assert!(display.len() < 40);
}
#[test]
fn test_message_id_debug() {
let response_id = ResponseId::from_u128(0x0001_0000_0000_002A_0000_0000_0000_1234);
let msg_id = MessageId::new(response_id);
let debug = format!("{:?}", msg_id);
assert!(debug.contains("MessageId"));
assert!(debug.contains("worker"));
assert!(debug.contains("slot"));
assert!(debug.contains("generation"));
}
#[test]
fn test_message_id_alternate_debug() {
let response_id = ResponseId::from_u128(0x0001_0000_0000_002A_0000_0000_0000_1234);
let msg_id = MessageId::new(response_id);
let debug = format!("{:#?}", msg_id);
assert!(debug.contains("MessageId"));
}
#[test]
fn test_message_id_conversion() {
let response_id = ResponseId::from_u128(12345);
let msg_id = MessageId::from(response_id);
let back: ResponseId = msg_id.into();
assert_eq!(response_id, back);
}
#[test]
fn test_base58_encoding_is_compact() {
let worker_id = 0x123456789ABCDEF0u64;
let encoded = MessageId::encode_u64_base58(worker_id);
assert!(encoded.len() < 16);
assert!(encoded.len() >= 10);
assert!(!encoded.contains('0'));
assert!(!encoded.contains('O'));
assert!(!encoded.contains('I'));
assert!(!encoded.contains('l'));
}
}