Merge pull request #2969 from TheBlueMatt/2024-03-fix-upgradable-enum
[rust-lightning] / lightning / src / util / string.rs
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 use crate::io::{self, Read};
14 use crate::ln::msgs;
15 use crate::util::ser::{Writeable, Writer, Readable};
16
17 #[allow(unused_imports)]
18 use crate::prelude::*;
19
20 /// Struct to `Display` fields in a safe way using `PrintableString`
21 #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
22 pub struct UntrustedString(pub String);
23
24 impl Writeable for UntrustedString {
25         fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
26                 self.0.write(w)
27         }
28 }
29
30 impl Readable for UntrustedString {
31         fn read<R: Read>(r: &mut R) -> Result<Self, msgs::DecodeError> {
32                 let s: String = Readable::read(r)?;
33                 Ok(Self(s))
34         }
35 }
36
37 impl fmt::Display for UntrustedString {
38         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39                 PrintableString(&self.0).fmt(f)
40         }
41 }
42
43 /// A string that displays only printable characters, replacing control characters with
44 /// [`core::char::REPLACEMENT_CHARACTER`].
45 #[derive(Debug, PartialEq)]
46 pub struct PrintableString<'a>(pub &'a str);
47
48 impl<'a> fmt::Display for PrintableString<'a> {
49         fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
50                 use core::fmt::Write;
51                 for c in self.0.chars() {
52                         let c = if c.is_control() { core::char::REPLACEMENT_CHARACTER } else { c };
53                         f.write_char(c)?;
54                 }
55
56                 Ok(())
57         }
58 }
59
60 #[cfg(test)]
61 mod tests {
62         use super::PrintableString;
63
64         #[test]
65         fn displays_printable_string() {
66                 assert_eq!(
67                         format!("{}", PrintableString("I \u{1F496} LDK!\t\u{26A1}")),
68                         "I \u{1F496} LDK!\u{FFFD}\u{26A1}",
69                 );
70         }
71 }