Skip to main content

qubit_text_codec/codec/
utf16_u16_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::utf16;
11use crate::{
12    Charset,
13    CharsetCodec,
14    CharsetDecodeResult,
15    CharsetEncodeResult,
16    DecodeStatus,
17    Utf16,
18};
19
20/// Combined UTF-16 `u16` code-unit codec.
21///
22/// `Utf16U16Codec` works with UTF-16 code units rather than serialized bytes.
23/// Use [`crate::Utf16ByteCodec`] when the input or output is a byte stream with an
24/// explicit byte order.
25///
26/// # Examples
27///
28/// ```rust
29/// use qubit_text_codec::{
30///     CharsetCodec,
31///     DecodeStatus,
32///     Charset,
33///     Utf16,
34///     Utf16U16Codec,
35/// };
36///
37/// let codec = Utf16U16Codec;
38/// assert_eq!(Charset::UTF_16, codec.charset());
39/// assert_eq!(Utf16::MAX_UNITS_PER_CHAR, codec.max_units_per_char());
40///
41/// let mut output = [0_u16; Utf16::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-16"),
49/// );
50/// ```
51#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
52pub struct Utf16U16Codec;
53
54impl Utf16U16Codec {
55    /// Returns the UTF-16 encoding descriptor.
56    ///
57    /// # Returns
58    ///
59    /// Returns [`Charset::UTF_16`].
60    #[must_use]
61    #[inline]
62    pub const fn charset(self) -> Charset {
63        Charset::UTF_16
64    }
65
66    /// Returns the maximum number of UTF-16 code units needed for one character.
67    ///
68    /// # Returns
69    ///
70    /// Returns [`Utf16::MAX_UNITS_PER_CHAR`].
71    #[must_use]
72    #[inline]
73    pub const fn max_units_per_char(self) -> usize {
74        Utf16::MAX_UNITS_PER_CHAR
75    }
76}
77
78impl CharsetCodec for Utf16U16Codec {
79    type Unit = u16;
80    /// Returns UTF-16 charset descriptor.
81    ///
82    /// # Returns
83    ///
84    /// Returns [`Charset::UTF_16`].
85    #[inline]
86    fn charset(&self) -> Charset {
87        Charset::UTF_16
88    }
89
90    /// Returns the maximum number of UTF-16 code units for one character.
91    ///
92    /// # Returns
93    ///
94    /// Returns [`Utf16::MAX_UNITS_PER_CHAR`].
95    #[inline]
96    fn max_units_per_char(&self) -> usize {
97        Utf16::MAX_UNITS_PER_CHAR
98    }
99
100    /// Decodes one UTF-16 scalar value from a `u16` prefix.
101    ///
102    /// # Arguments
103    ///
104    /// * `input` - UTF-16 code-unit slice.
105    /// * `index` - Start offset for parsing; must satisfy `index <= input.len()`.
106    ///
107    /// # Returns
108    ///
109    /// * `Ok(DecodeStatus::NeedMore { required, available })` when only a partial unit/pair
110    ///   is present.
111    /// * `Ok(DecodeStatus::Complete { value, consumed })` when one character is decoded.
112    ///
113    /// # Errors
114    ///
115    /// * [`crate::CharsetDecodeErrorKind::MalformedSequence`] for invalid
116    ///   surrogate combinations.
117    /// * [`crate::CharsetDecodeErrorKind::InvalidCodePoint`] when resulting
118    ///   scalar is invalid.
119    fn decode_one(&self, input: &[u16], index: usize) -> CharsetDecodeResult<DecodeStatus> {
120        utf16::decode_units_prefix(input, index)
121    }
122
123    /// Encodes one Unicode scalar value into UTF-16 code units at `index`.
124    ///
125    /// # Arguments
126    ///
127    /// * `ch` - The Unicode scalar value to encode.
128    /// * `output` - Destination `u16` buffer.
129    /// * `index` - Start offset where units are written; must satisfy
130    ///   `index <= output.len()`.
131    ///
132    /// # Returns
133    ///
134    /// `Ok(usize)` with the number of written UTF-16 units (`1` or `2`).
135    ///
136    /// # Errors
137    ///
138    /// * [`crate::CharsetEncodeErrorKind::BufferTooSmall`] if destination is
139    ///   insufficient.
140    fn encode_one(&self, ch: char, output: &mut [u16], index: usize) -> CharsetEncodeResult<usize> {
141        utf16::encode_units_char(ch, output, index)
142    }
143}