write16/
lib.rs

1// Copyright Mozilla Foundation
2//
3// Licensed under the Apache License (Version 2.0), or the MIT license,
4// (the "Licenses") at your option. You may not use this file except in
5// compliance with one of the Licenses. You may obtain copies of the
6// Licenses at:
7//
8//    https://www.apache.org/licenses/LICENSE-2.0
9//    https://opensource.org/licenses/MIT
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the Licenses is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the Licenses for the specific language governing permissions and
15// limitations under the Licenses.
16
17#![no_std]
18
19//! `write16` provides the trait `Write16`, which a UTF-16 analog of the
20//! `core::fmt::Write` trait (the sink part—not the formatting part).
21
22#[cfg(feature = "alloc")]
23extern crate alloc;
24#[cfg(feature = "arrayvec")]
25extern crate arrayvec;
26#[cfg(feature = "smallvec")]
27extern crate smallvec;
28
29/// A UTF-16 sink analogous to `core::fmt::Write`.
30pub trait Write16 {
31    /// Write a slice containing UTF-16 to the sink.
32    ///
33    /// The implementor of the trait should not validate UTF-16.
34    /// It's the responsibility of the caller to pass valid
35    /// UTF-16.
36    fn write_slice(&mut self, s: &[u16]) -> core::fmt::Result;
37
38    /// Write a Unicode scalar value to the sink.
39    #[inline(always)]
40    fn write_char(&mut self, c: char) -> core::fmt::Result {
41        let mut buf = [0u16; 2];
42        self.write_slice(c.encode_utf16(&mut buf))
43    }
44
45    /// A hint that the caller expects to write `upcoming` UTF-16
46    /// code units. The implementation must not assume `upcoming`
47    /// to be exact. The caller may write more or fewer code units
48    /// using `write_slice()` and `write_char()`. However, the
49    /// caller should try to give reasonable estimates if it uses
50    /// this method.
51    ///
52    /// For `Vec` and `SmallVec`, this maps to `reserve()`.
53    /// The default implementation does nothing.
54    #[inline(always)]
55    fn size_hint(&mut self, upcoming: usize) -> core::fmt::Result {
56        let _ = upcoming;
57        Ok(())
58    }
59}
60
61#[cfg(feature = "alloc")]
62impl Write16 for alloc::vec::Vec<u16> {
63    #[inline(always)]
64    fn write_slice(&mut self, s: &[u16]) -> core::fmt::Result {
65        self.extend_from_slice(s);
66        Ok(())
67    }
68
69    #[inline(always)]
70    fn write_char(&mut self, c: char) -> core::fmt::Result {
71        if c <= '\u{FFFF}' {
72            self.push(c as u16);
73        } else {
74            let mut buf = [0u16; 2];
75            let u = u32::from(c);
76            buf[0] = (0xD7C0 + (u >> 10)) as u16;
77            buf[1] = (0xDC00 + (u & 0x3FF)) as u16;
78            self.extend_from_slice(&mut buf);
79        }
80        Ok(())
81    }
82
83    #[inline(always)]
84    fn size_hint(&mut self, upcoming: usize) -> core::fmt::Result {
85        self.reserve(upcoming);
86        Ok(())
87    }
88}
89
90#[cfg(feature = "smallvec")]
91impl<A: smallvec::Array<Item = u16>> Write16 for smallvec::SmallVec<A> {
92    #[inline(always)]
93    fn write_slice(&mut self, s: &[u16]) -> core::fmt::Result {
94        self.extend_from_slice(s);
95        Ok(())
96    }
97
98    #[inline(always)]
99    fn write_char(&mut self, c: char) -> core::fmt::Result {
100        if c <= '\u{FFFF}' {
101            self.push(c as u16);
102        } else {
103            let mut buf = [0u16; 2];
104            let u = u32::from(c);
105            buf[0] = (0xD7C0 + (u >> 10)) as u16;
106            buf[1] = (0xDC00 + (u & 0x3FF)) as u16;
107            self.extend_from_slice(&mut buf);
108        }
109        Ok(())
110    }
111
112    #[inline(always)]
113    fn size_hint(&mut self, upcoming: usize) -> core::fmt::Result {
114        self.reserve(upcoming);
115        Ok(())
116    }
117}
118
119#[cfg(feature = "arrayvec")]
120impl<const CAP: usize> Write16 for arrayvec::ArrayVec<u16, CAP> {
121    #[inline(always)]
122    fn write_slice(&mut self, s: &[u16]) -> core::fmt::Result {
123        if self.try_extend_from_slice(s).is_ok() {
124            Ok(())
125        } else {
126            Err(core::fmt::Error {})
127        }
128    }
129
130    #[inline(always)]
131    fn write_char(&mut self, c: char) -> core::fmt::Result {
132        if c <= '\u{FFFF}' {
133            if self.try_push(c as u16).is_ok() {
134                Ok(())
135            } else {
136                Err(core::fmt::Error {})
137            }
138        } else {
139            let mut buf = [0u16; 2];
140            let u = u32::from(c);
141            buf[0] = (0xD7C0 + (u >> 10)) as u16;
142            buf[1] = (0xDC00 + (u & 0x3FF)) as u16;
143            self.write_slice(&mut buf)
144        }
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use crate::Write16;
151
152    #[cfg(feature = "alloc")]
153    #[test]
154    fn test_vec() {
155        let mut v: alloc::vec::Vec<u16> = alloc::vec::Vec::new();
156        assert_eq!(v.capacity(), 0);
157        assert!(v.size_hint(32).is_ok());
158        assert!(v.capacity() >= 32);
159        assert_eq!(v.len(), 0);
160        assert!(v.write_slice([0x0061u16, 0x0062u16].as_slice()).is_ok());
161        assert_eq!(v.len(), 2);
162        assert!(v.write_char('☃').is_ok());
163        assert_eq!(v.len(), 3);
164        assert!(v.write_char('😊').is_ok());
165        assert_eq!(v.len(), 5);
166        assert_eq!(
167            v.as_slice(),
168            [0x0061u16, 0x0062u16, 0x2603u16, 0xD83Du16, 0xDE0Au16].as_slice()
169        );
170    }
171
172    #[cfg(feature = "smallvec")]
173    #[test]
174    fn test_smallvec() {
175        let mut v: smallvec::SmallVec<[u16; 2]> = smallvec::SmallVec::new();
176        assert_eq!(v.capacity(), 2);
177        assert!(v.size_hint(32).is_ok());
178        assert!(v.capacity() >= 32);
179        assert_eq!(v.len(), 0);
180        assert!(v.write_slice([0x0061u16, 0x0062u16].as_slice()).is_ok());
181        assert_eq!(v.len(), 2);
182        assert!(v.write_char('☃').is_ok());
183        assert_eq!(v.len(), 3);
184        assert!(v.write_char('😊').is_ok());
185        assert_eq!(v.len(), 5);
186        assert_eq!(
187            v.as_slice(),
188            [0x0061u16, 0x0062u16, 0x2603u16, 0xD83Du16, 0xDE0Au16].as_slice()
189        );
190    }
191
192    #[cfg(feature = "arrayvec")]
193    #[test]
194    fn test_arrayvec() {
195        let mut v: arrayvec::ArrayVec<u16, 4> = arrayvec::ArrayVec::new();
196        assert_eq!(v.capacity(), 4);
197        assert!(v.size_hint(32).is_ok());
198        assert_eq!(v.capacity(), 4);
199        assert_eq!(v.len(), 0);
200        assert!(v.write_char('😊').is_ok());
201        assert_eq!(v.len(), 2);
202        assert!(v.write_char('☃').is_ok());
203        assert_eq!(v.len(), 3);
204        assert!(v.write_char('😊').is_err());
205        assert_eq!(v.len(), 3);
206        assert_eq!(v.as_slice(), [0xD83Du16, 0xDE0Au16, 0x2603u16].as_slice());
207    }
208}