capnp/
text.rs

1// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
2// Licensed under the MIT License:
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21
22//! UTF-8 encoded text.
23//!
24//! A `text::Reader<'a>` wraps a `&'a [u8]` that is expected but not guaranteed
25//! to contain UTF-8 encoded text.
26
27use core::str;
28
29use crate::Result;
30
31#[derive(Copy, Clone)]
32pub struct Owned(());
33
34impl crate::traits::Owned for Owned {
35    type Reader<'a> = Reader<'a>;
36    type Builder<'a> = Builder<'a>;
37}
38
39impl crate::introspect::Introspect for Owned {
40    fn introspect() -> crate::introspect::Type {
41        crate::introspect::TypeVariant::Text.into()
42    }
43}
44
45/// Wrapper around utf-8 encoded text.
46/// This is defined as a tuple struct to allow pattern matching
47/// on it via byte literals (for example `text::Reader(b"hello")`).
48#[derive(Copy, Clone, PartialEq, PartialOrd)]
49pub struct Reader<'a>(pub &'a [u8]);
50
51impl<'a> core::cmp::PartialEq<&'a str> for Reader<'a> {
52    #[inline]
53    fn eq(&self, other: &&'a str) -> bool {
54        self.as_bytes() == other.as_bytes()
55    }
56}
57
58impl<'a> core::cmp::PartialEq<Reader<'a>> for &'a str {
59    #[inline]
60    fn eq(&self, other: &Reader<'a>) -> bool {
61        self.as_bytes() == other.as_bytes()
62    }
63}
64
65#[cfg(feature = "alloc")]
66impl core::cmp::PartialEq<alloc::string::String> for Reader<'_> {
67    #[inline]
68    fn eq(&self, other: &alloc::string::String) -> bool {
69        self.as_bytes() == other.as_bytes()
70    }
71}
72
73#[cfg(feature = "alloc")]
74impl<'a> core::cmp::PartialEq<Reader<'a>> for alloc::string::String {
75    #[inline]
76    fn eq(&self, other: &Reader<'a>) -> bool {
77        self.as_bytes() == other.as_bytes()
78    }
79}
80
81impl<'a> core::cmp::PartialOrd<&'a str> for Reader<'a> {
82    #[inline]
83    fn partial_cmp(&self, other: &&'a str) -> Option<core::cmp::Ordering> {
84        self.as_bytes().partial_cmp(other.as_bytes())
85    }
86}
87
88impl<'a> core::cmp::PartialOrd<Reader<'a>> for &'a str {
89    #[inline]
90    fn partial_cmp(&self, other: &Reader<'a>) -> Option<core::cmp::Ordering> {
91        self.as_bytes().partial_cmp(other.as_bytes())
92    }
93}
94
95impl core::fmt::Debug for Reader<'_> {
96    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
97        match self.to_str() {
98            Ok(s) => write!(f, "{s:?}"),
99            Err(_) => write!(f, "<invalid utf-8: {:?}>", self.as_bytes()),
100        }
101    }
102}
103
104impl<'a> From<&'a str> for Reader<'a> {
105    #[inline]
106    fn from(value: &'a str) -> Self {
107        Self(value.as_bytes())
108    }
109}
110
111impl<'a> From<&'a [u8]> for Reader<'a> {
112    #[inline]
113    fn from(value: &'a [u8]) -> Self {
114        Self(value)
115    }
116}
117
118impl<'a, const N: usize> From<&'a [u8; N]> for Reader<'a> {
119    fn from(value: &'a [u8; N]) -> Self {
120        Self(&value[..])
121    }
122}
123
124impl<'a> TryFrom<Reader<'a>> for &'a str {
125    type Error = core::str::Utf8Error;
126    fn try_from(value: Reader<'a>) -> core::result::Result<&'a str, core::str::Utf8Error> {
127        let Reader(v) = value;
128        str::from_utf8(v)
129    }
130}
131
132impl<'a> crate::traits::FromPointerReader<'a> for Reader<'a> {
133    fn get_from_pointer(
134        reader: &crate::private::layout::PointerReader<'a>,
135        default: Option<&'a [crate::Word]>,
136    ) -> Result<Reader<'a>> {
137        reader.get_text(default)
138    }
139}
140
141impl<'a> Reader<'a> {
142    /// The string's length, in bytes.
143    #[inline]
144    pub fn len(&self) -> usize {
145        self.as_bytes().len()
146    }
147
148    #[inline]
149    pub fn is_empty(&self) -> bool {
150        self.len() == 0
151    }
152
153    #[inline]
154    pub fn as_bytes(self) -> &'a [u8] {
155        let Self(d) = self;
156        d
157    }
158
159    /// Converts to a `str`, returning a error if the data contains invalid utf-8.
160    #[inline]
161    pub fn to_str(self) -> core::result::Result<&'a str, core::str::Utf8Error> {
162        let Self(s) = self;
163        str::from_utf8(s)
164    }
165
166    #[cfg(feature = "alloc")]
167    /// Converts to a `String`, returning a error if the data contains invalid utf-8.
168    #[inline]
169    pub fn to_string(self) -> core::result::Result<alloc::string::String, core::str::Utf8Error> {
170        Ok(self.to_str()?.into())
171    }
172}
173
174pub struct Builder<'a> {
175    /// Does not include the trailing null byte.
176    bytes: &'a mut [u8],
177
178    /// Position at which `push_ascii()` and `push_str()` will write to.
179    pos: usize,
180}
181
182impl core::cmp::PartialEq for Builder<'_> {
183    fn eq(&self, other: &Self) -> bool {
184        self.bytes == other.bytes
185    }
186}
187
188impl<'a> core::cmp::PartialEq<&'a str> for Builder<'a> {
189    fn eq(&self, other: &&'a str) -> bool {
190        self.bytes == other.as_bytes()
191    }
192}
193
194impl<'a> core::cmp::PartialEq<Builder<'a>> for &'a str {
195    fn eq(&self, other: &Builder<'a>) -> bool {
196        self.as_bytes() == other.bytes
197    }
198}
199
200impl<'a> Builder<'a> {
201    #[inline]
202    pub fn new(bytes: &mut [u8]) -> Builder<'_> {
203        Builder { bytes, pos: 0 }
204    }
205
206    #[inline]
207    pub fn with_pos(bytes: &mut [u8], pos: usize) -> Builder<'_> {
208        Builder { bytes, pos }
209    }
210
211    /// The string's length, in bytes.
212    #[inline]
213    pub fn len(&self) -> usize {
214        self.bytes.len()
215    }
216
217    #[inline]
218    pub fn is_empty(&self) -> bool {
219        self.len() == 0
220    }
221
222    #[inline]
223    pub fn as_bytes(self) -> &'a [u8] {
224        self.bytes
225    }
226
227    /// Converts to a `str`, returning a error if the data contains invalid utf-8.
228    #[inline]
229    pub fn to_str(self) -> core::result::Result<&'a str, core::str::Utf8Error> {
230        str::from_utf8(self.bytes)
231    }
232
233    #[cfg(feature = "alloc")]
234    /// Converts to a `String`, returning a error if the data contains invalid utf-8.
235    #[inline]
236    pub fn to_string(self) -> core::result::Result<alloc::string::String, core::str::Utf8Error> {
237        Ok(self.to_str()?.into())
238    }
239
240    #[inline]
241    pub fn as_bytes_mut(self) -> &'a mut [u8] {
242        &mut self.bytes[..]
243    }
244
245    /// Writes a single ascii character at position `pos` and increments `pos`.
246    #[inline]
247    pub fn push_ascii(&mut self, ascii: u8) {
248        assert!(ascii < 128);
249        self.bytes[self.pos] = ascii;
250        self.pos += 1;
251    }
252
253    /// Writes a string at position `pos` and increases `pos` a corresponding amount.
254    #[inline]
255    pub fn push_str(&mut self, string: &str) {
256        let bytes = string.as_bytes();
257        self.bytes[self.pos..(self.pos + bytes.len())].copy_from_slice(bytes);
258        self.pos += bytes.len();
259    }
260
261    /// Zeroes all data and resets `pos`.
262    pub fn clear(&mut self) {
263        for b in &mut self.bytes[..self.pos] {
264            *b = 0;
265        }
266        self.pos = 0;
267    }
268
269    #[inline]
270    pub fn reborrow(&mut self) -> Builder<'_> {
271        Builder {
272            bytes: self.bytes,
273            pos: self.pos,
274        }
275    }
276
277    #[inline]
278    pub fn into_reader(self) -> Reader<'a> {
279        Reader(self.bytes)
280    }
281
282    #[inline]
283    pub fn reborrow_as_reader(&self) -> Reader<'_> {
284        Reader(self.bytes)
285    }
286}
287
288impl core::fmt::Debug for Builder<'_> {
289    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
290        match self.reborrow_as_reader().to_str() {
291            Ok(s) => write!(f, "{s:?}"),
292            Err(_) => write!(f, "<invalid utf-8>"),
293        }
294    }
295}
296
297impl<'a> crate::traits::FromPointerBuilder<'a> for Builder<'a> {
298    fn init_pointer(builder: crate::private::layout::PointerBuilder<'a>, size: u32) -> Builder<'a> {
299        builder.init_text(size)
300    }
301    fn get_from_pointer(
302        builder: crate::private::layout::PointerBuilder<'a>,
303        default: Option<&'a [crate::Word]>,
304    ) -> Result<Builder<'a>> {
305        builder.get_text(default)
306    }
307}
308
309impl<'a> crate::traits::SetterInput<Owned> for Reader<'a> {
310    #[inline]
311    fn set_pointer_builder<'b>(
312        mut pointer: crate::private::layout::PointerBuilder<'b>,
313        value: Reader<'a>,
314        _canonicalize: bool,
315    ) -> Result<()> {
316        pointer.set_text(value);
317        Ok(())
318    }
319}
320
321// Allow text fields to be set with &str or String or anything
322// else that implements `AsRef<str>`.
323impl<T: AsRef<str>> crate::traits::SetterInput<Owned> for T {
324    #[inline]
325    fn set_pointer_builder(
326        mut pointer: crate::private::layout::PointerBuilder<'_>,
327        value: T,
328        _canonicalize: bool,
329    ) -> Result<()> {
330        pointer.set_text(value.as_ref().into());
331        Ok(())
332    }
333}
334
335impl<'a> From<Reader<'a>> for crate::dynamic_value::Reader<'a> {
336    fn from(t: Reader<'a>) -> crate::dynamic_value::Reader<'a> {
337        crate::dynamic_value::Reader::Text(t)
338    }
339}
340
341impl<'a> From<&'a str> for crate::dynamic_value::Reader<'a> {
342    fn from(t: &'a str) -> crate::dynamic_value::Reader<'a> {
343        crate::dynamic_value::Reader::Text(t.into())
344    }
345}
346
347impl<'a> From<Builder<'a>> for crate::dynamic_value::Builder<'a> {
348    fn from(t: Builder<'a>) -> crate::dynamic_value::Builder<'a> {
349        crate::dynamic_value::Builder::Text(t)
350    }
351}