Skip to main content

asteroid_mq_model/
node.rs

1use std::sync;
2
3use serde::{Deserialize, Serialize};
4use typeshare::typeshare;
5
6#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
7#[typeshare(serialized_as = "string")]
8pub struct NodeId {
9    pub bytes: [u8; 16],
10}
11
12impl Serialize for NodeId {
13    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
14        if serializer.is_human_readable() {
15            serializer.serialize_str(&self.to_base64())
16        } else {
17            <[u8; 16]>::serialize(&self.bytes, serializer)
18        }
19    }
20}
21
22impl<'de> Deserialize<'de> for NodeId {
23    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
24    where
25        D: serde::Deserializer<'de>,
26    {
27        use serde::de::Error;
28        if deserializer.is_human_readable() {
29            let s = <&'de str>::deserialize(deserializer)?;
30            NodeId::from_base64(s).map_err(D::Error::custom)
31        } else {
32            let bytes = <[u8; 16]>::deserialize(deserializer)?;
33            Ok(NodeId { bytes })
34        }
35    }
36}
37
38impl From<u64> for NodeId {
39    fn from(id: u64) -> Self {
40        Self::new_indexed(id)
41    }
42}
43
44impl std::fmt::Debug for NodeId {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        f.debug_tuple("NodeId")
47            .field(&crate::util::dashed(&[
48                crate::util::hex(&self.bytes[0..1]),
49                crate::util::hex(&self.bytes[1..9]),
50                crate::util::hex(&self.bytes[9..10]),
51                crate::util::hex(&self.bytes[10..16]),
52            ]))
53            .finish()
54    }
55}
56
57impl std::fmt::Display for NodeId {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        write!(
60            f,
61            "{}-{}-{}-{}",
62            crate::util::hex(&self.bytes[0..1]),
63            crate::util::hex(&self.bytes[1..9]),
64            crate::util::hex(&self.bytes[9..10]),
65            crate::util::hex(&self.bytes[10..16]),
66        )
67    }
68}
69
70impl NodeId {
71    pub const KIND_INDEXED: u8 = 0x00;
72    pub const KIND_SHA256: u8 = 0x01;
73    pub const KIND_SNOWFLAKE: u8 = 0x02;
74    pub const fn new_indexed(id: u64) -> Self {
75        let mut bytes = [0; 16];
76        bytes[0] = Self::KIND_INDEXED;
77        let index_part = id.to_be_bytes();
78        bytes[1] = index_part[0];
79        bytes[2] = index_part[1];
80        bytes[3] = index_part[2];
81        bytes[4] = index_part[3];
82        bytes[5] = index_part[4];
83        bytes[6] = index_part[5];
84        bytes[7] = index_part[6];
85        bytes[8] = index_part[7];
86        NodeId { bytes }
87    }
88    pub fn sha256(bytes: &[u8]) -> Self {
89        let dg = <sha2::Sha256 as sha2::Digest>::digest(bytes);
90        let mut bytes = [0; 16];
91        bytes[0] = Self::KIND_SHA256;
92        bytes[1..16].copy_from_slice(&dg.as_slice()[0..15]);
93        NodeId { bytes }
94    }
95    pub fn snowflake() -> NodeId {
96        static INSTANCE_ID: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(0);
97        let dg = crate::util::executor_digest();
98        let mut bytes = [0; 16];
99        bytes[0] = Self::KIND_SNOWFLAKE;
100        bytes[1..9].copy_from_slice(&dg.to_be_bytes());
101        bytes[9..10].copy_from_slice(
102            &INSTANCE_ID
103                .fetch_add(1, sync::atomic::Ordering::SeqCst)
104                .to_be_bytes(),
105        );
106        bytes[10..16].copy_from_slice(&(crate::util::timestamp_sec()).to_be_bytes()[2..8]);
107        NodeId { bytes }
108    }
109    pub fn to_base64(&self) -> String {
110        use base64::Engine;
111        base64::engine::general_purpose::URL_SAFE.encode(self.bytes)
112    }
113    pub fn from_base64(s: &str) -> Result<Self, base64::DecodeError> {
114        use base64::Engine;
115        let id = base64::engine::general_purpose::URL_SAFE.decode(s)?;
116        let mut bytes = [0u8; 16];
117        bytes.copy_from_slice(&id);
118        Ok(Self { bytes })
119    }
120}