Skip to content

Commit 80cf03e

Browse files
committed
types: init basic skeleton and copy chars.rs from uefi-crate
1 parent 95b5746 commit 80cf03e

File tree

6 files changed

+208
-3
lines changed

6 files changed

+208
-3
lines changed

Cargo.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[package]
22
name = "ucs2"
3-
version = "0.3.3"
4-
authors = ["Gabriel Majeri <[email protected]>", "Fredrik Aleksander", "Isaac Woods"]
5-
description = "UCS-2 decoding and encoding functions"
3+
version = "0.4.0"
4+
authors = ["The Rust OSDev team"]
5+
description = "UCS-2 decoding and encoding functions as well as convenient types."
66
repository = "https://github.com/rust-osdev/ucs2-rs"
77
keywords = ["ucs2", "no-std", "encoding"]
88
categories = ["encoding", "no-std"]
@@ -13,3 +13,6 @@ rust-version = "1.56"
1313
[dependencies]
1414
bit_field = "0.10"
1515

16+
[features]
17+
default = []
18+
alloc = []

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@
44
#![deny(missing_docs)]
55
#![deny(clippy::all)]
66

7+
#[cfg(feature = "alloc")]
8+
extern crate alloc;
9+
710
pub mod encoding;
11+
pub mod types;

src/types/chars.rs

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
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::{self, Display, Formatter};
7+
8+
/// Character conversion error
9+
#[derive(Clone, Copy, Debug)]
10+
pub struct CharConversionError;
11+
12+
impl Display for CharConversionError {
13+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
14+
write!(f, "{self:?}")
15+
}
16+
}
17+
18+
#[cfg(feature = "unstable")]
19+
impl core::error::Error for CharConversionError {}
20+
21+
/// A Latin-1 character
22+
#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord, Hash)]
23+
#[repr(transparent)]
24+
pub struct Char8(u8);
25+
26+
impl TryFrom<char> for Char8 {
27+
type Error = CharConversionError;
28+
29+
fn try_from(value: char) -> Result<Self, Self::Error> {
30+
let code_point = u32::from(value);
31+
u8::try_from(code_point)
32+
.map(Char8)
33+
.map_err(|_| CharConversionError)
34+
}
35+
}
36+
37+
impl From<Char8> for char {
38+
fn from(char: Char8) -> Self {
39+
Self::from(char.0)
40+
}
41+
}
42+
43+
impl From<u8> for Char8 {
44+
fn from(value: u8) -> Self {
45+
Self(value)
46+
}
47+
}
48+
49+
impl From<Char8> for u8 {
50+
fn from(char: Char8) -> Self {
51+
char.0
52+
}
53+
}
54+
55+
impl fmt::Debug for Char8 {
56+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57+
<char as fmt::Debug>::fmt(&From::from(self.0), f)
58+
}
59+
}
60+
61+
impl fmt::Display for Char8 {
62+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63+
<char as fmt::Display>::fmt(&From::from(self.0), f)
64+
}
65+
}
66+
67+
impl PartialEq<char> for Char8 {
68+
fn eq(&self, other: &char) -> bool {
69+
u32::from(self.0) == u32::from(*other)
70+
}
71+
}
72+
73+
/// Latin-1 version of the NUL character
74+
pub const NUL_8: Char8 = Char8(0);
75+
76+
/// An UCS-2 code point
77+
#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord, Hash)]
78+
#[repr(transparent)]
79+
pub struct Char16(u16);
80+
81+
impl Char16 {
82+
/// Creates a UCS-2 character from a Rust character without checks.
83+
///
84+
/// # Safety
85+
/// The caller must be sure that the character is valid.
86+
#[must_use]
87+
pub const unsafe fn from_u16_unchecked(val: u16) -> Self {
88+
Self(val)
89+
}
90+
91+
/// Checks if the value is within the ASCII range.
92+
#[must_use]
93+
pub const fn is_ascii(&self) -> bool {
94+
self.0 <= 127
95+
}
96+
}
97+
98+
impl TryFrom<char> for Char16 {
99+
type Error = CharConversionError;
100+
101+
fn try_from(value: char) -> Result<Self, Self::Error> {
102+
let code_point = u32::from(value);
103+
u16::try_from(code_point)
104+
.map(Char16)
105+
.map_err(|_| CharConversionError)
106+
}
107+
}
108+
109+
impl From<Char16> for char {
110+
fn from(char: Char16) -> Self {
111+
u32::from(char.0).try_into().unwrap()
112+
}
113+
}
114+
115+
impl TryFrom<u16> for Char16 {
116+
type Error = CharConversionError;
117+
118+
fn try_from(value: u16) -> Result<Self, Self::Error> {
119+
// We leverage char's TryFrom<u32> impl for Unicode validity checking
120+
let res: Result<char, _> = u32::from(value).try_into();
121+
if let Ok(ch) = res {
122+
ch.try_into()
123+
} else {
124+
Err(CharConversionError)
125+
}
126+
}
127+
}
128+
129+
impl From<Char16> for u16 {
130+
fn from(char: Char16) -> Self {
131+
char.0
132+
}
133+
}
134+
135+
impl fmt::Debug for Char16 {
136+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137+
if let Ok(c) = u32::from(self.0).try_into() {
138+
<char as fmt::Debug>::fmt(&c, f)
139+
} else {
140+
write!(f, "Char16({:?})", self.0)
141+
}
142+
}
143+
}
144+
145+
impl fmt::Display for Char16 {
146+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147+
if let Ok(c) = u32::from(self.0).try_into() {
148+
<char as fmt::Display>::fmt(&c, f)
149+
} else {
150+
write!(f, "{}", core::char::REPLACEMENT_CHARACTER)
151+
}
152+
}
153+
}
154+
155+
impl PartialEq<char> for Char16 {
156+
fn eq(&self, other: &char) -> bool {
157+
u32::from(self.0) == u32::from(*other)
158+
}
159+
}
160+
161+
/// UCS-2 version of the NUL character
162+
pub const NUL_16: Char16 = unsafe { Char16::from_u16_unchecked(0) };
163+
164+
#[cfg(test)]
165+
mod tests {
166+
use super::*;
167+
168+
#[test]
169+
fn test_char8_from_char() {
170+
assert_eq!(Char8::try_from('A').unwrap(), Char8(0x41));
171+
}
172+
173+
#[test]
174+
fn test_char16_from_char() {
175+
assert_eq!(Char16::try_from('A').unwrap(), Char16(0x41));
176+
assert_eq!(Char16::try_from('ꋃ').unwrap(), Char16(0xa2c3));
177+
}
178+
179+
/// Test that `Char8` and `Char16` can be directly compared with `char`.
180+
#[test]
181+
fn test_char_eq() {
182+
let primitive_char: char = 'A';
183+
assert_eq!(Char8(0x41), primitive_char);
184+
assert_eq!(Char16(0x41), primitive_char);
185+
}
186+
}

src/types/cstr16.rs

Whitespace-only changes.

src/types/cstr8.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//! Rusty-types to work with UCS-2 strings and for convenient interoperability
2+
//! with Rust string literals (`&str`) and Rust strings (`String`).
3+

src/types/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
pub(self) mod chars;
3+
mod cstr8;
4+
#[cfg(feature = "alloc")]
5+
mod cstr16;
6+
7+
pub use cstr8::*;
8+
#[cfg(feature = "alloc")]
9+
pub use cstr16::*;

0 commit comments

Comments
 (0)