use crate::siphash::hash_name_u32;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct ServiceId(u32);
impl ServiceId {
pub fn from_name(name: &str) -> Self {
Self(hash_name_u32(name))
}
pub const fn from_raw(id: u32) -> Self {
Self(id)
}
pub const fn as_u32(&self) -> u32 {
self.0
}
}
impl From<ServiceId> for u32 {
fn from(id: ServiceId) -> u32 {
id.0
}
}
impl From<u32> for ServiceId {
fn from(id: u32) -> ServiceId {
ServiceId(id)
}
}
impl fmt::Display for ServiceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ServiceId(0x{:08X})", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct InterfaceId(u32);
impl InterfaceId {
pub fn from_name(name: &str) -> Self {
Self(hash_name_u32(name))
}
pub const fn from_raw(id: u32) -> Self {
Self(id)
}
pub const fn as_u32(&self) -> u32 {
self.0
}
}
impl From<InterfaceId> for u32 {
fn from(id: InterfaceId) -> u32 {
id.0
}
}
impl From<u32> for InterfaceId {
fn from(id: u32) -> InterfaceId {
InterfaceId(id)
}
}
impl fmt::Display for InterfaceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "InterfaceId(0x{:08X})", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct MethodId(u32);
impl MethodId {
pub fn from_name(name: &str) -> Self {
Self(hash_name_u32(name))
}
pub const fn from_raw(id: u32) -> Self {
Self(id)
}
pub const fn as_u32(&self) -> u32 {
self.0
}
}
impl From<MethodId> for u32 {
fn from(id: MethodId) -> u32 {
id.0
}
}
impl From<u32> for MethodId {
fn from(id: u32) -> MethodId {
MethodId(id)
}
}
impl fmt::Display for MethodId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MethodId(0x{:08X})", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct HeaderKeyId(u32);
impl HeaderKeyId {
pub fn from_name(name: &str) -> Self {
Self(hash_name_u32(name))
}
pub const fn from_raw(id: u32) -> Self {
Self(id)
}
pub const fn as_u32(&self) -> u32 {
self.0
}
}
impl From<HeaderKeyId> for u32 {
fn from(id: HeaderKeyId) -> u32 {
id.0
}
}
impl From<u32> for HeaderKeyId {
fn from(id: u32) -> HeaderKeyId {
HeaderKeyId(id)
}
}
impl fmt::Display for HeaderKeyId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "HeaderKeyId(0x{:08X})", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct MetricId(u32);
impl MetricId {
pub fn from_name(name: &str) -> Self {
Self(hash_name_u32(name))
}
pub const fn from_raw(id: u32) -> Self {
Self(id)
}
pub const fn as_u32(&self) -> u32 {
self.0
}
}
impl From<MetricId> for u32 {
fn from(id: MetricId) -> u32 {
id.0
}
}
impl From<u32> for MetricId {
fn from(id: u32) -> MetricId {
MetricId(id)
}
}
impl fmt::Display for MetricId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MetricId(0x{:08X})", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct InstanceId(u128);
impl InstanceId {
pub fn new_random() -> Self {
let uuid = uuid::Uuid::new_v4();
Self(u128::from_be_bytes(*uuid.as_bytes()))
}
pub const fn from_raw(id: u128) -> Self {
Self(id)
}
pub fn from_bytes(bytes: [u8; 16]) -> Self {
Self(u128::from_be_bytes(bytes))
}
pub const fn as_u128(&self) -> u128 {
self.0
}
pub fn as_bytes(&self) -> [u8; 16] {
self.0.to_be_bytes()
}
}
impl From<InstanceId> for u128 {
fn from(id: InstanceId) -> u128 {
id.0
}
}
impl From<u128> for InstanceId {
fn from(id: u128) -> InstanceId {
InstanceId(id)
}
}
impl fmt::Display for InstanceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "InstanceId(0x{:032X})", self.0)
}
}
pub mod well_known {
use super::HeaderKeyId;
use once_cell::sync::Lazy;
pub static TRACE_ID: Lazy<HeaderKeyId> = Lazy::new(|| HeaderKeyId::from_name("trace_id"));
pub static SPAN_ID: Lazy<HeaderKeyId> = Lazy::new(|| HeaderKeyId::from_name("span_id"));
pub static REQUEST_ID: Lazy<HeaderKeyId> = Lazy::new(|| HeaderKeyId::from_name("request_id"));
pub static CALLER_SERVICE: Lazy<HeaderKeyId> =
Lazy::new(|| HeaderKeyId::from_name("caller_service"));
pub static IDEMPOTENCY_KEY: Lazy<HeaderKeyId> =
Lazy::new(|| HeaderKeyId::from_name("idempotency_key"));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_service_id() {
let id1 = ServiceId::from_name("user-service");
let id2 = ServiceId::from_name("user-service");
let id3 = ServiceId::from_name("payment-service");
assert_eq!(id1, id2, "Same name should produce same ID");
assert_ne!(id1, id3, "Different names should produce different IDs");
let raw: u32 = id1.into();
let restored = ServiceId::from_raw(raw);
assert_eq!(id1, restored);
}
#[test]
fn test_interface_id() {
let id = InterfaceId::from_name("mensa.user.v2.UserInterface");
let raw = id.as_u32();
let restored = InterfaceId::from_raw(raw);
assert_eq!(id, restored);
}
#[test]
fn test_method_id() {
let get_user = MethodId::from_name("GetUser");
let create_user = MethodId::from_name("CreateUser");
assert_ne!(get_user, create_user);
}
#[test]
fn test_header_key_id() {
let trace_id = HeaderKeyId::from_name("trace_id");
let request_id = HeaderKeyId::from_name("request_id");
assert_ne!(trace_id, request_id);
}
#[test]
fn test_metric_id() {
let request_count = MetricId::from_name("request_count");
let error_count = MetricId::from_name("error_count");
assert_ne!(request_count, error_count);
}
#[test]
fn test_instance_id() {
let id1 = InstanceId::new_random();
let bytes = id1.as_bytes();
let restored = InstanceId::from_bytes(bytes);
assert_eq!(id1, restored);
assert_eq!(bytes.len(), 16);
}
#[test]
fn test_display() {
let service_id = ServiceId::from_name("test-service");
let display = format!("{}", service_id);
assert!(display.starts_with("ServiceId(0x"));
}
#[test]
fn test_well_known_headers() {
assert_eq!(*well_known::TRACE_ID, HeaderKeyId::from_name("trace_id"));
assert_eq!(*well_known::SPAN_ID, HeaderKeyId::from_name("span_id"));
assert_eq!(
*well_known::REQUEST_ID,
HeaderKeyId::from_name("request_id")
);
assert_eq!(
*well_known::CALLER_SERVICE,
HeaderKeyId::from_name("caller_service")
);
assert_eq!(
*well_known::IDEMPOTENCY_KEY,
HeaderKeyId::from_name("idempotency_key")
);
assert_ne!(*well_known::TRACE_ID, *well_known::SPAN_ID);
}
#[test]
fn test_version_sensitivity() {
let v1 = InterfaceId::from_name("mensa.user.v1.UserInterface");
let v2 = InterfaceId::from_name("mensa.user.v2.UserInterface");
assert_ne!(v1, v2, "Different versions should have different IDs");
}
#[test]
fn test_ordering() {
let id1 = ServiceId::from_name("aaa");
let id2 = ServiceId::from_name("bbb");
let id3 = ServiceId::from_name("ccc");
let mut ids = [id3, id1, id2];
ids.sort();
assert_eq!(ids.len(), 3);
}
}