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
6use core::fmt;
7
8/// Character conversion error
9#[derive(Clone, Copy, Debug)]
10pub struct CharConversionError;
11
12/// A Latin-1 character
13#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)]
14#[repr(transparent)]
15pub struct Char8(u8);
16
17impl 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
30impl From<Char8> for char {
31 fn from(char: Char8) -> char {
32 char.0 as char
33 }
34}
35
36impl From<u8> for Char8 {
37 fn from(value: u8) -> Self {
38 Char8(value)
39 }
40}
41
42impl From<Char8> for u8 {
43 fn from(char: Char8) -> u8 {
44 char.0
45 }
46}
47
48impl 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
54impl 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
61pub 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)]
66pub struct Char16(u16);
67
68impl 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
81impl From<Char16> for char {
82 fn from(char: Char16) -> char {
83 u32::from(char.0).try_into().unwrap()
84 }
85}
86
87impl 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
101impl From<Char16> for u16 {
102 fn from(char: Char16) -> u16 {
103 char.0
104 }
105}
106
107impl 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
117impl 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
128pub const NUL_16: Char16 = Char16(0);
129