oi4_dnp_encoding/
encode.rs1use core::fmt;
2
3#[inline]
4pub(crate) const fn is_unreserved(b: u8) -> bool {
5 matches!(b,
6 b'A'..=b'Z' |
7 b'a'..=b'z' |
8 b'0'..=b'9' |
9 b'-' | b'.' | b'_' | b'~'
10 )
11}
12
13const HEX_UPPER: &[u8; 16] = b"0123456789ABCDEF";
14
15pub fn encoded_len(input: &str) -> usize {
17 let bytes = input.as_bytes();
18 let mut i = 0usize;
19 let mut len = 0usize;
20 while i < bytes.len() {
21 let b = bytes[i];
22 if b < 0x80 {
23 if is_unreserved(b) {
25 len += 1;
26 } else {
27 len += 3;
28 }
29 i += 1;
30 } else {
31 let seq_len = if b & 0b1110_0000 == 0b1100_0000 {
34 2
35 } else if b & 0b1111_0000 == 0b1110_0000 {
36 3
37 } else {
38 4
39 };
40 len += seq_len;
41 i += seq_len;
42 }
43 }
44 len
45}
46
47pub fn encode_into(input: &str, out: &mut impl fmt::Write) -> fmt::Result {
49 let mut buf = [0u8; 4];
50 for ch in input.chars() {
51 if ch.is_ascii() {
52 let b = ch as u8;
53 if is_unreserved(b) {
54 out.write_char(ch)?;
55 } else {
56 let hi = HEX_UPPER[(b >> 4) as usize] as char;
57 let lo = HEX_UPPER[(b & 0x0F) as usize] as char;
58 out.write_char(',')?;
59 out.write_char(hi)?;
60 out.write_char(lo)?;
61 }
62 } else {
63 let s = ch.encode_utf8(&mut buf);
64 out.write_str(s)?;
65 }
66 }
67 Ok(())
68}
69
70#[cfg(feature = "alloc")]
71pub fn encode(input: &str) -> alloc::string::String {
72 let mut s = alloc::string::String::with_capacity(encoded_len(input));
73 encode_into(input, &mut s).expect("write to String cannot fail");
74 s
75}