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