Skip to content

Commit 48bb9ed

Browse files
committed
Add PrintableString utility
Strings defined by third parties may contain control characters. Provide a wrapper such that these are replaced when displayed. Useful in node aliases and offer fields.
1 parent 50aeee5 commit 48bb9ed

File tree

3 files changed

+47
-10
lines changed

3 files changed

+47
-10
lines changed

lightning/src/routing/gossip.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer, MaybeReadable}
3131
use crate::util::logger::{Logger, Level};
3232
use crate::util::events::{Event, EventHandler, MessageSendEvent, MessageSendEventsProvider};
3333
use crate::util::scid_utils::{block_from_scid, scid_from_parts, MAX_SCID_BLOCK};
34+
use crate::util::string::PrintableString;
3435

3536
use crate::io;
3637
use crate::io_extras::{copy, sink};
@@ -1022,23 +1023,17 @@ pub struct NodeAlias(pub [u8; 32]);
10221023

10231024
impl fmt::Display for NodeAlias {
10241025
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1025-
let control_symbol = core::char::REPLACEMENT_CHARACTER;
10261026
let first_null = self.0.iter().position(|b| *b == 0).unwrap_or(self.0.len());
10271027
let bytes = self.0.split_at(first_null).0;
10281028
match core::str::from_utf8(bytes) {
1029-
Ok(alias) => {
1030-
for c in alias.chars() {
1031-
let mut bytes = [0u8; 4];
1032-
let c = if !c.is_control() { c } else { control_symbol };
1033-
f.write_str(c.encode_utf8(&mut bytes))?;
1034-
}
1035-
},
1029+
Ok(alias) => PrintableString(alias).fmt(f)?,
10361030
Err(_) => {
1031+
use core::fmt::Write;
10371032
for c in bytes.iter().map(|b| *b as char) {
10381033
// Display printable ASCII characters
1039-
let mut bytes = [0u8; 4];
1034+
let control_symbol = core::char::REPLACEMENT_CHARACTER;
10401035
let c = if c >= '\x20' && c <= '\x7e' { c } else { control_symbol };
1041-
f.write_str(c.encode_utf8(&mut bytes))?;
1036+
f.write_char(c)?;
10421037
}
10431038
},
10441039
};

lightning/src/util/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub mod ser;
2121
pub mod message_signing;
2222
pub mod invoice;
2323
pub mod persist;
24+
pub mod string;
2425
pub mod wakers;
2526

2627
pub(crate) mod atomic_counter;

lightning/src/util/string.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// This file is Copyright its original authors, visible in version control
2+
// history.
3+
//
4+
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5+
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7+
// You may not use this file except in accordance with one or both of these
8+
// licenses.
9+
10+
//! Utilities for strings.
11+
12+
use core::fmt;
13+
14+
/// A string that displays only printable characters, replacing control characters with
15+
/// [`core::char::REPLACEMENT_CHARACTER`].
16+
pub struct PrintableString<'a>(pub &'a str);
17+
18+
impl<'a> fmt::Display for PrintableString<'a> {
19+
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
20+
use core::fmt::Write;
21+
for c in self.0.chars() {
22+
let c = if c.is_control() { core::char::REPLACEMENT_CHARACTER } else { c };
23+
f.write_char(c)?;
24+
}
25+
26+
Ok(())
27+
}
28+
}
29+
30+
#[cfg(test)]
31+
mod tests {
32+
use super::PrintableString;
33+
34+
#[test]
35+
fn displays_printable_string() {
36+
assert_eq!(
37+
format!("{}", PrintableString("I \u{1F496} LDK!\t\u{26A1}")),
38+
"I \u{1F496} LDK!\u{FFFD}\u{26A1}",
39+
);
40+
}
41+
}

0 commit comments

Comments
 (0)