Skip to main content

lexe_common/ln/
node_alias.rs

1use std::fmt::{self, Write};
2
3use lexe_serde::hexstr_or_bytes;
4use lightning::routing::gossip::NodeAlias;
5use lightning_types::string::PrintableString;
6#[cfg(any(test, feature = "test-utils"))]
7use proptest_derive::Arbitrary;
8use serde::{Deserialize, Serialize};
9
10/// Newtype for [`NodeAlias`].
11#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
12#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
13pub struct LxNodeAlias(#[serde(with = "hexstr_or_bytes")] pub [u8; 32]);
14
15impl LxNodeAlias {
16    pub const fn from_str(s: &str) -> Self {
17        let len = s.len();
18        let input = s.as_bytes();
19
20        debug_assert!(s.len() <= 32);
21
22        let mut out = [0u8; 32];
23        let mut idx = 0;
24        loop {
25            if idx >= len {
26                break;
27            }
28            out[idx] = input[idx];
29            idx += 1;
30        }
31
32        Self(out)
33    }
34}
35
36impl From<NodeAlias> for LxNodeAlias {
37    fn from(alias: NodeAlias) -> Self {
38        Self(alias.0)
39    }
40}
41impl From<LxNodeAlias> for NodeAlias {
42    fn from(alias: LxNodeAlias) -> Self {
43        Self(alias.0)
44    }
45}
46
47impl fmt::Debug for LxNodeAlias {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "LxNodeAlias({self})")
50    }
51}
52
53impl fmt::Display for LxNodeAlias {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        // This block is basically copied from `NodeAlias`'s `Display` impl.
56        // - If bytes are valid UTF-8, display its printable characters.
57        // - If bytes are not UTF-8, display its printable ASCII characters.
58        let first_null =
59            self.0.iter().position(|b| *b == 0).unwrap_or(self.0.len());
60        let bytes = self.0.split_at(first_null).0;
61        match std::str::from_utf8(bytes) {
62            Ok(alias) => PrintableString(alias).fmt(f)?,
63            Err(_) =>
64                for b in bytes.iter() {
65                    let c = if (b'\x20'..=b'\x7e').contains(b) {
66                        *b as char
67                    } else {
68                        char::REPLACEMENT_CHARACTER
69                    };
70                    f.write_char(c)?;
71                },
72        }
73
74        Ok(())
75    }
76}