devela/text/translit/ascii/
fns.rs1use crate::{Translit, UnicodeScalar, is, whilst};
4
5impl Translit {
6 #[must_use]
21 pub const fn ascii(char: char) -> &'static str {
22 Self::ascii_scalar(char as u32)
23 }
24 #[doc = crate::_doc_vendor!("transliteration")]
29 #[must_use]
30 pub const fn ascii_scalar(scalar: u32) -> &'static str {
31 let block = (scalar >> 8) as usize;
32 let offset = (scalar & 0xFF) as usize;
33 if block < Translit::ASCII_BLOCKS.len() {
34 let block_data = Translit::ASCII_BLOCKS[block];
35 if offset < block_data.len() {
36 return block_data[offset];
37 }
38 }
39 ""
40 }
41 #[must_use]
43 pub fn ascii_of<S: UnicodeScalar>(scalar: S) -> &'static str {
44 Self::ascii_scalar(scalar.to_scalar())
45 }
46
47 #[must_use]
49 pub const fn has_ascii(c: char) -> bool {
50 !Self::ascii(c).is_empty()
51 }
52 #[must_use]
54 pub const fn has_ascii_scalar(scalar: u32) -> bool {
55 !Self::ascii_scalar(scalar).is_empty()
56 }
57
58 #[must_use]
60 pub const fn ascii_or(c: char, fallback: &'static str) -> &'static str {
61 let out = Self::ascii(c);
62 if out.is_empty() { fallback } else { out }
63 }
64 #[must_use]
66 pub const fn ascii_scalar_or(scalar: u32, fallback: &'static str) -> &'static str {
67 let out = Self::ascii_scalar(scalar);
68 if out.is_empty() { fallback } else { out }
69 }
70
71 #[must_use]
73 pub const fn ascii_byte(c: char) -> Option<u8> {
74 Self::ascii_scalar_byte(c as u32)
75 }
76 #[must_use]
78 pub const fn ascii_scalar_byte(scalar: u32) -> Option<u8> {
79 let out = Self::ascii_scalar(scalar);
80 let bytes = out.as_bytes();
81 if bytes.len() == 1 { Some(bytes[0]) } else { None }
82 }
83
84 #[must_use]
86 pub const fn ascii_len(c: char) -> usize {
87 Self::ascii(c).len()
88 }
89 #[must_use]
91 pub const fn ascii_scalar_len(scalar: u32) -> usize {
92 Self::ascii_scalar(scalar).len()
93 }
94}
95impl Translit {
96 pub fn write_ascii(src: &str, dst: &mut [u8]) -> Option<usize> {
102 let mut written = 0;
103 for c in src.chars() {
104 let out = Self::ascii(c).as_bytes();
105 is! { written + out.len() > dst.len(), return None }
106 whilst! { i in 0..out.len(); { dst[written + i] = out[i]; }}
107 written += out.len();
108 }
109 Some(written)
110 }
111 pub fn write_ascii_or(src: &str, dst: &mut [u8], fallback: &str) -> Option<usize> {
116 let mut written = 0;
117 for c in src.chars() {
118 let out = Self::ascii(c);
119 let out = if out.is_empty() { fallback } else { out };
120 let bytes = out.as_bytes();
121 is! { written + bytes.len() > dst.len(), return None }
122 whilst! { i in 0..bytes.len(); { dst[written + i] = bytes[i]; }}
123 written += bytes.len();
124 }
125 Some(written)
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::Translit;
132
133 #[test]
134 fn ascii() {
135 assert_eq![Translit::ascii_scalar('°' as u32), "deg"];
136 assert_eq![Translit::ascii_scalar('α' as u32), "a"];
137 assert_eq![Translit::ascii_scalar('©' as u32), "(c)"];
138 assert_eq![Translit::ascii_scalar('㍱' as u32), "HPA"];
139 assert_eq![Translit::ascii_scalar('㎮' as u32), "rad/s"];
140 assert_eq![Translit::ascii_scalar('中' as u32), "Zhong "];
141 assert_eq![Translit::ascii_scalar('ff' as u32), "ff"];
142 assert_eq![Translit::ascii_scalar('ﬤ' as u32), "k"];
143 assert_eq![Translit::ascii_scalar('�' as u32), ""];
144 assert_eq![Translit::ascii_scalar('🚀' as u32), ""];
145 }
146}