1mod hash;
14mod type_description;
15mod type_id;
16
17pub use hash::{calculate_hash, to_ros2_json};
18pub use type_description::{
19 FieldDescription, FieldTypeDescription, TypeDescription, TypeDescriptionMsg, to_hash_version,
20};
21pub use type_id::TypeId;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub struct TypeHash(pub [u8; 32]);
26
27impl TypeHash {
28 pub fn to_rihs_string(&self) -> String {
30 format!("RIHS01_{}", hex::encode(self.0))
31 }
32
33 pub fn from_rihs_string(s: &str) -> Result<Self, String> {
35 if !s.starts_with("RIHS01_") {
36 return Err("Invalid RIHS01 format: must start with 'RIHS01_'".to_string());
37 }
38
39 let hex_part = &s[7..];
40 let bytes = hex::decode(hex_part).map_err(|e| format!("Invalid hex encoding: {}", e))?;
41
42 if bytes.len() != 32 {
43 return Err(format!("Hash must be 32 bytes, got {}", bytes.len()));
44 }
45
46 let mut hash = [0u8; 32];
47 hash.copy_from_slice(&bytes);
48 Ok(TypeHash(hash))
49 }
50
51 pub fn zero() -> Self {
53 TypeHash([0u8; 32])
54 }
55}
56
57impl std::fmt::Display for TypeHash {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 write!(f, "{}", self.to_rihs_string())
60 }
61}
62
63impl Default for TypeHash {
64 fn default() -> Self {
65 Self::zero()
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_type_hash_roundtrip() {
75 let hash = TypeHash([
76 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
77 0x77, 0x88, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
78 0x66, 0x77, 0x88, 0x99,
79 ]);
80
81 let s = hash.to_rihs_string();
82 assert!(s.starts_with("RIHS01_"));
83 assert_eq!(s.len(), 7 + 64); let decoded = TypeHash::from_rihs_string(&s).unwrap();
86 assert_eq!(hash, decoded);
87 }
88
89 #[test]
90 fn test_type_hash_invalid_prefix() {
91 let result = TypeHash::from_rihs_string("INVALID_1234");
92 assert!(result.is_err());
93 }
94
95 #[test]
96 fn test_type_hash_invalid_length() {
97 let result = TypeHash::from_rihs_string("RIHS01_1234");
98 assert!(result.is_err());
99 }
100}