qubit_text_codec/codec/utf32_u32_codec.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10use super::inner::utf32;
11use crate::{
12 Charset,
13 CharsetCodec,
14 CharsetDecodeResult,
15 CharsetEncodeResult,
16 DecodeStatus,
17 Utf32,
18};
19
20/// Combined UTF-32 `u32` code-unit codec.
21///
22/// `Utf32U32Codec` works with raw UTF-32 scalar-value units rather than
23/// serialized bytes. Use [`crate::Utf32ByteCodec`] for byte streams with an
24/// explicit byte order.
25///
26/// # Examples
27///
28/// ```rust
29/// use qubit_text_codec::{
30/// CharsetCodec,
31/// DecodeStatus,
32/// Charset,
33/// Utf32,
34/// Utf32U32Codec,
35/// };
36///
37/// let codec = Utf32U32Codec;
38/// assert_eq!(Charset::UTF_32, codec.charset());
39/// assert_eq!(Utf32::MAX_UNITS_PER_CHAR, codec.max_units_per_char());
40///
41/// let mut output = [0_u32; Utf32::MAX_UNITS_PER_CHAR];
42/// let written = codec.encode_one('中', &mut output, 0).expect("buffer fits");
43/// assert_eq!(
44/// DecodeStatus::Complete {
45/// value: '中',
46/// consumed: written,
47/// },
48/// codec.decode_one(&output[..written], 0).expect("valid UTF-32"),
49/// );
50/// ```
51#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
52pub struct Utf32U32Codec;
53
54impl Utf32U32Codec {
55 /// Returns the UTF-32 encoding descriptor.
56 ///
57 /// # Returns
58 ///
59 /// Returns [`Charset::UTF_32`].
60 #[must_use]
61 #[inline]
62 pub const fn charset(self) -> Charset {
63 Charset::UTF_32
64 }
65
66 /// Returns the maximum number of UTF-32 code units needed for one character.
67 ///
68 /// # Returns
69 ///
70 /// Returns [`Utf32::MAX_UNITS_PER_CHAR`].
71 #[must_use]
72 #[inline]
73 pub const fn max_units_per_char(self) -> usize {
74 Utf32::MAX_UNITS_PER_CHAR
75 }
76}
77
78impl CharsetCodec for Utf32U32Codec {
79 type Unit = u32;
80 /// Returns UTF-32 charset descriptor.
81 ///
82 /// # Returns
83 ///
84 /// Returns [`Charset::UTF_32`].
85 #[inline]
86 fn charset(&self) -> Charset {
87 Charset::UTF_32
88 }
89
90 /// Returns the fixed size (1 unit) for one UTF-32 scalar value.
91 ///
92 /// # Returns
93 ///
94 /// Returns [`Utf32::MAX_UNITS_PER_CHAR`].
95 #[inline]
96 fn max_units_per_char(&self) -> usize {
97 Utf32::MAX_UNITS_PER_CHAR
98 }
99
100 /// Decodes one UTF-32 scalar value from a `u32` prefix.
101 ///
102 /// # Arguments
103 ///
104 /// * `input` - UTF-32 unit slice.
105 /// * `index` - Start offset for parsing; must satisfy `index <= input.len()`.
106 ///
107 /// # Returns
108 ///
109 /// * `Ok(DecodeStatus::NeedMore { required, available })` when no unit is available.
110 /// * `Ok(DecodeStatus::Complete { value, consumed })` with `consumed == 1`.
111 ///
112 /// # Errors
113 ///
114 /// * [`crate::CharsetDecodeErrorKind::MalformedSequence`] when index is out
115 /// of bounds.
116 /// * [`crate::CharsetDecodeErrorKind::InvalidCodePoint`] when unit is not a
117 /// valid scalar.
118 fn decode_one(&self, input: &[u32], index: usize) -> CharsetDecodeResult<DecodeStatus> {
119 utf32::decode_units_prefix(input, index)
120 }
121
122 /// Encodes one Unicode scalar value into a `u32` unit at `index`.
123 ///
124 /// # Arguments
125 ///
126 /// * `ch` - The Unicode scalar value to encode.
127 /// * `output` - Destination `u32` buffer.
128 /// * `index` - Start offset where one unit is written; must satisfy
129 /// `index < output.len()`.
130 ///
131 /// # Returns
132 ///
133 /// Always returns `Ok(1)` on success.
134 ///
135 /// # Errors
136 ///
137 /// * [`crate::CharsetEncodeErrorKind::BufferTooSmall`] if `output` has no
138 /// room at `index`.
139 fn encode_one(&self, ch: char, output: &mut [u32], index: usize) -> CharsetEncodeResult<usize> {
140 utf32::encode_units_char(ch, output, index)
141 }
142}