1 | //! UEFI character handling |
2 | //! |
3 | //! UEFI uses both Latin-1 and UCS-2 character encoding, this module implements |
4 | //! support for the associated character types. |
5 | |
6 | use core::fmt; |
7 | |
8 | /// Character conversion error |
9 | #[derive (Clone, Copy, Debug)] |
10 | pub struct CharConversionError; |
11 | |
12 | /// A Latin-1 character |
13 | #[derive (Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] |
14 | #[repr (transparent)] |
15 | pub struct Char8(u8); |
16 | |
17 | impl TryFrom<char> for Char8 { |
18 | type Error = CharConversionError; |
19 | |
20 | fn try_from(value: char) -> Result<Self, Self::Error> { |
21 | let code_point: u32 = value as u32; |
22 | if code_point <= 0xff { |
23 | Ok(Char8(code_point as u8)) |
24 | } else { |
25 | Err(CharConversionError) |
26 | } |
27 | } |
28 | } |
29 | |
30 | impl From<Char8> for char { |
31 | fn from(char: Char8) -> char { |
32 | char.0 as char |
33 | } |
34 | } |
35 | |
36 | impl From<u8> for Char8 { |
37 | fn from(value: u8) -> Self { |
38 | Char8(value) |
39 | } |
40 | } |
41 | |
42 | impl From<Char8> for u8 { |
43 | fn from(char: Char8) -> u8 { |
44 | char.0 |
45 | } |
46 | } |
47 | |
48 | impl fmt::Debug for Char8 { |
49 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
50 | <char as fmt::Debug>::fmt(&From::from(self.0), f) |
51 | } |
52 | } |
53 | |
54 | impl fmt::Display for Char8 { |
55 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
56 | <char as fmt::Display>::fmt(&From::from(self.0), f) |
57 | } |
58 | } |
59 | |
60 | /// Latin-1 version of the NUL character |
61 | pub const NUL_8: Char8 = Char8(0); |
62 | |
63 | /// An UCS-2 code point |
64 | #[derive (Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] |
65 | #[repr (transparent)] |
66 | pub struct Char16(u16); |
67 | |
68 | impl TryFrom<char> for Char16 { |
69 | type Error = CharConversionError; |
70 | |
71 | fn try_from(value: char) -> Result<Self, Self::Error> { |
72 | let code_point: u32 = value as u32; |
73 | if code_point <= 0xffff { |
74 | Ok(Char16(code_point as u16)) |
75 | } else { |
76 | Err(CharConversionError) |
77 | } |
78 | } |
79 | } |
80 | |
81 | impl From<Char16> for char { |
82 | fn from(char: Char16) -> char { |
83 | u32::from(char.0).try_into().unwrap() |
84 | } |
85 | } |
86 | |
87 | impl TryFrom<u16> for Char16 { |
88 | type Error = CharConversionError; |
89 | |
90 | fn try_from(value: u16) -> Result<Self, Self::Error> { |
91 | // We leverage char's TryFrom<u32> impl for Unicode validity checking |
92 | let res: Result<char, _> = u32::from(value).try_into(); |
93 | if let Ok(ch: char) = res { |
94 | ch.try_into() |
95 | } else { |
96 | Err(CharConversionError) |
97 | } |
98 | } |
99 | } |
100 | |
101 | impl From<Char16> for u16 { |
102 | fn from(char: Char16) -> u16 { |
103 | char.0 |
104 | } |
105 | } |
106 | |
107 | impl fmt::Debug for Char16 { |
108 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
109 | if let Ok(c: char) = u32::from(self.0).try_into() { |
110 | <char as fmt::Debug>::fmt(&c, f) |
111 | } else { |
112 | write!(f, "Char16( {:?})" , self.0) |
113 | } |
114 | } |
115 | } |
116 | |
117 | impl fmt::Display for Char16 { |
118 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
119 | if let Ok(c: char) = u32::from(self.0).try_into() { |
120 | <char as fmt::Display>::fmt(&c, f) |
121 | } else { |
122 | write!(f, " {}" , core::char::REPLACEMENT_CHARACTER) |
123 | } |
124 | } |
125 | } |
126 | |
127 | /// UCS-2 version of the NUL character |
128 | pub const NUL_16: Char16 = Char16(0); |
129 | |