textos/unicode/egc/
non_nul.rs1use crate::{
11 error::{TextosError as Error, TextosResult as Result},
12 macros::impl_sized_alias,
13 unicode::{
14 char::*,
15 egc::Egcs,
16 string::{StaticNonNulString, Strings},
17 },
18};
19#[cfg(feature = "alloc")]
20use alloc::{ffi::CString, str::Chars};
21use core::fmt;
22use devela::codegen::paste;
23#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
30#[repr(transparent)]
31pub struct StaticNonNulEgc<const CAP: usize>(StaticNonNulString<CAP>);
32
33impl_sized_alias![
34 NonNulEgc, StaticNonNulEgc,
35 "<abbr title='Extended Grapheme Cluster'>EGC</abbr>, with fixed capacity of ",
36 ", no nul chars.":
37 "An" 8, 1 "";
38 "A" 16, 2 "s";
39 "A" 24, 3 "s";
40 "A" 32, 4 "s";
41 "A" 40, 5 "s";
42 "A" 48, 6 "s";
43 "A" 56, 7 "s";
44 "A" 64, 8 "s";
45 "A" 128, 16 "s"
46];
47
48impl<const CAP: usize> StaticNonNulEgc<CAP> {
51 #[inline]
53 pub const fn new() -> Self {
54 Self(StaticNonNulString::new())
55 }
56
57 #[inline]
66 #[must_use]
67 pub const fn from_char7(c: Char7) -> Self {
68 Self(StaticNonNulString::from_char7(c))
69 }
70
71 #[inline]
80 #[must_use]
81 pub const fn from_char8(c: Char8) -> Self {
82 Self(StaticNonNulString::from_char8(c))
83 }
84
85 #[inline]
94 #[must_use]
95 pub const fn from_char16(c: Char16) -> Self {
96 Self(StaticNonNulString::from_char16(c))
97 }
98
99 #[inline]
108 #[must_use]
109 pub const fn from_char24(c: Char24) -> Self {
110 Self(StaticNonNulString::from_char24(c))
111 }
112
113 #[inline]
122 #[must_use]
123 pub const fn from_char32(c: Char32) -> Self {
124 Self(StaticNonNulString::from_char32(c))
125 }
126
127 #[inline]
136 #[must_use]
137 pub const fn from_char(c: char) -> Self {
138 Self::from_char32(Char32(c))
139 }
140
141 pub fn len(&self) -> usize {
145 self.0.len()
146 }
147
148 pub fn is_empty(&self) -> bool {
150 self.0.len() == 0
151 }
152
153 #[inline]
155 pub const fn capacity() -> usize {
156 CAP
157 }
158
159 #[inline]
161 pub fn remaining_capacity(&self) -> usize {
162 CAP - self.len()
163 }
164
165 #[inline]
167 pub fn is_full(&self) -> bool {
168 self.len() == CAP
169 }
170
171 #[inline]
173 pub fn clear(&mut self) {
174 self.0.clear();
175 }
176
177 #[inline]
181 pub fn as_bytes(&self) -> &[u8] {
182 self.0.as_bytes()
183 }
184
185 #[inline]
187 #[cfg(feature = "unsafe")]
188 #[cfg_attr(feature = "nightly", doc(cfg(feature = "unsafe")))]
189 pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
190 self.0.as_bytes_mut()
191 }
192
193 #[inline]
197 pub fn as_array(&self) -> [u8; CAP] {
198 self.0.as_array()
199 }
200
201 #[inline]
205 pub fn into_array(self) -> [u8; CAP] {
206 self.0.into_array()
207 }
208
209 #[inline]
211 pub fn as_str(&self) -> &str {
212 self.0.as_str()
213 }
214
215 #[cfg(feature = "unsafe")]
217 #[cfg_attr(feature = "nightly", doc(cfg(feature = "unsafe")))]
218 pub unsafe fn as_str_mut(&mut self) -> &mut str {
219 self.0.as_str_mut()
220 }
221
222 #[cfg(feature = "alloc")]
224 #[cfg_attr(feature = "nightly", doc(cfg(feature = "alloc")))]
225 pub fn chars(&self) -> Chars {
226 self.0.chars()
227 }
228
229 #[inline]
231 #[cfg(feature = "alloc")]
232 #[cfg_attr(feature = "nightly", doc(cfg(feature = "alloc")))]
233 pub fn to_cstring(&self) -> CString {
234 self.0.to_cstring()
235 }
236
237 }
239
240impl<const CAP: usize> Strings for StaticNonNulEgc<CAP> {}
243impl<const CAP: usize> Egcs for StaticNonNulEgc<CAP> {}
244
245mod core_impls {
246 use super::*;
247
248 impl<const CAP: usize> Default for StaticNonNulEgc<CAP> {
249 #[inline]
251 fn default() -> Self {
252 Self::new()
253 }
254 }
255
256 impl<const CAP: usize> fmt::Display for StaticNonNulEgc<CAP> {
257 #[inline]
258 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259 write!(f, "{}", self.0)
260 }
261 }
262 impl<const CAP: usize> fmt::Debug for StaticNonNulEgc<CAP> {
263 #[inline]
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 write!(f, "{:?}", self.0)
266 }
267 }
268
269 }
286
287macro_rules! impl_from_char {
290 ( $char:ty => $for_name:ident: $( $for_bit:expr ),+ ) => {
294 $( impl_from_char![@$char => $for_name: $for_bit]; )+
295 };
296 ( @$char:ty => $for_name:ident: $for_bit:expr ) => { paste! {
297 impl From<$char> for [< $for_name $for_bit >] {
298 fn from(c: $char) -> [< $for_name $for_bit >] {
299 let mut s = Self::new();
300 let _ = s.0.push(c.into());
301 s
302 }
303 }
304 }};
305 ( try $char:ty => $for_name:ident: $( $for_bit:expr ),+ ) => {
306 $( impl_from_char![@try $char => $for_name: $for_bit]; )+
307 };
308 ( @try $char:ty => $for_name:ident: $for_bit:expr ) => { paste! {
309 impl TryFrom<$char> for [< $for_name $for_bit >] {
310 type Error = Error;
311 fn try_from(c: $char) -> Result<[< $for_name $for_bit >]> {
312 let mut s = Self::new();
313 s.0.try_push(c.into())?;
314 Ok(s)
315 }
316 }
317 }};
318}
319impl_from_char![Char7 => NonNulEgc: 8, 16, 24, 32, 40, 48, 56, 64, 128];
320impl_from_char![Char8 => NonNulEgc: 16, 24, 32, 40, 48, 56, 64, 128];
321impl_from_char![try Char8 => NonNulEgc: 8];
322impl_from_char![Char16 => NonNulEgc: 24, 32, 40, 48, 56, 64, 128];
323impl_from_char![try Char16 => NonNulEgc: 8, 16];
324impl_from_char![Char24 => NonNulEgc: 32, 40, 48, 56, 64, 128];
325impl_from_char![try Char24 => NonNulEgc: 8, 16, 24];
326impl_from_char![Char32 => NonNulEgc: 32, 40, 48, 56, 64, 128];
327impl_from_char![try Char32 => NonNulEgc: 8, 16, 24];
328impl_from_char![char => NonNulEgc: 32, 40, 48, 56, 64, 128];
329impl_from_char![try char => NonNulEgc: 8, 16, 24];