capnp/
primitive_list.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//! List of primitives.
23
24use core::marker;
25
26use crate::introspect;
27use crate::private::layout::{
28    data_bits_per_element, ListBuilder, ListReader, PointerBuilder, PointerReader, PrimitiveElement,
29};
30use crate::traits::{FromPointerBuilder, FromPointerReader, IndexMove, ListIter};
31use crate::Result;
32
33#[derive(Clone, Copy)]
34pub struct Owned<T> {
35    marker: marker::PhantomData<T>,
36}
37
38impl<T> introspect::Introspect for Owned<T>
39where
40    T: introspect::Introspect,
41{
42    fn introspect() -> introspect::Type {
43        introspect::Type::list_of(T::introspect())
44    }
45}
46
47impl<T> crate::traits::Owned for Owned<T>
48where
49    T: PrimitiveElement + introspect::Introspect,
50{
51    type Reader<'a> = Reader<'a, T>;
52    type Builder<'a> = Builder<'a, T>;
53}
54
55#[derive(Clone, Copy)]
56pub struct Reader<'a, T>
57where
58    T: PrimitiveElement,
59{
60    marker: marker::PhantomData<T>,
61    reader: ListReader<'a>,
62}
63
64impl<'a, T: PrimitiveElement> Reader<'a, T> {
65    pub fn len(&self) -> u32 {
66        self.reader.len()
67    }
68
69    pub fn is_empty(&self) -> bool {
70        self.len() == 0
71    }
72
73    pub fn iter(self) -> ListIter<Reader<'a, T>, T> {
74        let l = self.len();
75        ListIter::new(self, l)
76    }
77}
78
79impl<'a, T: PrimitiveElement> FromPointerReader<'a> for Reader<'a, T> {
80    fn get_from_pointer(
81        reader: &PointerReader<'a>,
82        default: Option<&'a [crate::Word]>,
83    ) -> Result<Reader<'a, T>> {
84        Ok(Reader {
85            reader: reader.get_list(T::element_size(), default)?,
86            marker: marker::PhantomData,
87        })
88    }
89}
90
91impl<T: PrimitiveElement> IndexMove<u32, T> for Reader<'_, T> {
92    fn index_move(&self, index: u32) -> T {
93        self.get(index)
94    }
95}
96
97impl<T: PrimitiveElement> Reader<'_, T> {
98    /// Gets the `T` at position `index`. Panics if `index` is greater than or
99    /// equal to `len()`.
100    pub fn get(&self, index: u32) -> T {
101        assert!(index < self.len());
102        PrimitiveElement::get(&self.reader, index)
103    }
104
105    /// Gets the `T` at position `index`. Returns `None` if `index`
106    /// is greater than or equal to `len()`.
107    pub fn try_get(&self, index: u32) -> Option<T> {
108        if index < self.len() {
109            Some(PrimitiveElement::get(&self.reader, index))
110        } else {
111            None
112        }
113    }
114
115    const _CHECK_SLICE: () = check_slice_supported::<T>();
116
117    /// Attempts to return a view of the list as a native Rust slice.
118    /// Returns `None` if the elements of the list are non-contiguous,
119    /// which can happen if the schema has evolved.
120    ///
121    /// This method raises a compile-time error if `T` is larger than one
122    /// byte and either the `unaligned` feature is enabled or the target
123    /// is big-endian.
124    pub fn as_slice(&self) -> Option<&[T]> {
125        let () = Self::_CHECK_SLICE;
126        if self.reader.get_element_size() == T::element_size() {
127            let bytes = self.reader.into_raw_bytes();
128            let bits_per_element = data_bits_per_element(T::element_size()) as usize;
129            let slice_length = if bits_per_element > 0 {
130                8 * bytes.len() / bits_per_element
131            } else {
132                // This is a List(Void).
133                self.len() as usize
134            };
135            if slice_length == 0 {
136                Some(&[])
137            } else {
138                Some(unsafe {
139                    core::slice::from_raw_parts(bytes.as_ptr() as *const T, slice_length)
140                })
141            }
142        } else {
143            None
144        }
145    }
146}
147
148const fn check_slice_supported<T: PrimitiveElement>() {
149    if core::mem::size_of::<T>() > 1 {
150        if !cfg!(target_endian = "little") {
151            panic!("cannot call as_slice on primitive list of multi-byte elements on non-little endian targets");
152        }
153        if cfg!(feature = "unaligned") {
154            panic!("cannot call as_slice on primitive list of multi-byte elements when unaligned feature is enabled");
155        }
156    }
157}
158
159impl<'a, T> crate::traits::IntoInternalListReader<'a> for Reader<'a, T>
160where
161    T: PrimitiveElement,
162{
163    fn into_internal_list_reader(self) -> ListReader<'a> {
164        self.reader
165    }
166}
167
168pub struct Builder<'a, T>
169where
170    T: PrimitiveElement,
171{
172    marker: marker::PhantomData<T>,
173    builder: ListBuilder<'a>,
174}
175
176impl<'a, T> Builder<'a, T>
177where
178    T: PrimitiveElement,
179{
180    pub fn len(&self) -> u32 {
181        self.builder.len()
182    }
183
184    pub fn is_empty(&self) -> bool {
185        self.len() == 0
186    }
187
188    pub fn into_reader(self) -> Reader<'a, T> {
189        Reader {
190            marker: marker::PhantomData,
191            reader: self.builder.into_reader(),
192        }
193    }
194
195    pub fn set(&mut self, index: u32, value: T) {
196        assert!(index < self.len());
197        PrimitiveElement::set(&self.builder, index, value);
198    }
199
200    const _CHECK_SLICE: () = check_slice_supported::<T>();
201
202    /// Attempts to return a view of the list as a native Rust slice.
203    /// Returns `None` if the elements of the list are non-contiguous,
204    /// which can happen if the schema has evolved.
205    ///
206    /// This method raises a compile-time error if `T` is larger than one
207    /// byte and either the `unaligned` feature is enabled or the target
208    /// is big-endian.
209    pub fn as_slice(&mut self) -> Option<&mut [T]> {
210        let () = Self::_CHECK_SLICE;
211        if self.builder.get_element_size() == T::element_size() {
212            let bytes = self.builder.as_raw_bytes();
213            let bits_per_element = data_bits_per_element(T::element_size()) as usize;
214            let slice_length = if bits_per_element > 0 {
215                8 * bytes.len() / bits_per_element
216            } else {
217                // This is a List(Void).
218                self.len() as usize
219            };
220            if slice_length == 0 {
221                Some(&mut [])
222            } else {
223                Some(unsafe {
224                    core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut T, slice_length)
225                })
226            }
227        } else {
228            None
229        }
230    }
231}
232
233impl<'a, T: PrimitiveElement> FromPointerBuilder<'a> for Builder<'a, T> {
234    fn init_pointer(builder: PointerBuilder<'a>, size: u32) -> Builder<'a, T> {
235        Builder {
236            builder: builder.init_list(T::element_size(), size),
237            marker: marker::PhantomData,
238        }
239    }
240    fn get_from_pointer(
241        builder: PointerBuilder<'a>,
242        default: Option<&'a [crate::Word]>,
243    ) -> Result<Builder<'a, T>> {
244        Ok(Builder {
245            builder: builder.get_list(T::element_size(), default)?,
246            marker: marker::PhantomData,
247        })
248    }
249}
250
251impl<T: PrimitiveElement> Builder<'_, T> {
252    /// Gets the `T` at position `index`. Panics if `index` is greater than or
253    /// equal to `len()`.
254    pub fn get(&self, index: u32) -> T {
255        assert!(index < self.len());
256        PrimitiveElement::get_from_builder(&self.builder, index)
257    }
258
259    /// Gets the `T` at position `index`. Returns `None` if `index`
260    /// is greater than or equal to `len()`.
261    pub fn try_get(&self, index: u32) -> Option<T> {
262        if index < self.len() {
263            Some(PrimitiveElement::get_from_builder(&self.builder, index))
264        } else {
265            None
266        }
267    }
268
269    pub fn reborrow(&mut self) -> Builder<'_, T> {
270        Builder {
271            marker: marker::PhantomData,
272            builder: self.builder.reborrow(),
273        }
274    }
275}
276
277impl<'a, T> crate::traits::SetterInput<Owned<T>> for Reader<'a, T>
278where
279    T: PrimitiveElement,
280{
281    #[inline]
282    fn set_pointer_builder<'b>(
283        mut pointer: PointerBuilder<'b>,
284        value: Reader<'a, T>,
285        canonicalize: bool,
286    ) -> Result<()> {
287        pointer.set_list(&value.reader, canonicalize)
288    }
289}
290
291impl<'a, T> crate::traits::SetterInput<Owned<T>> for &'a [T]
292where
293    T: PrimitiveElement + Copy,
294{
295    #[inline]
296    fn set_pointer_builder<'b>(
297        pointer: PointerBuilder<'b>,
298        value: &'a [T],
299        _canonicalize: bool,
300    ) -> Result<()> {
301        let builder =
302            pointer.init_list(<T as PrimitiveElement>::element_size(), value.len() as u32);
303        for (idx, v) in value.iter().enumerate() {
304            PrimitiveElement::set(&builder, idx as u32, *v)
305        }
306        Ok(())
307    }
308}
309
310impl<'a, T, const N: usize> crate::traits::SetterInput<Owned<T>> for &'a [T; N]
311where
312    T: PrimitiveElement + Copy,
313{
314    #[inline]
315    fn set_pointer_builder<'b>(
316        pointer: PointerBuilder<'b>,
317        value: &'a [T; N],
318        canonicalize: bool,
319    ) -> Result<()> {
320        crate::traits::SetterInput::set_pointer_builder(pointer, &value[..], canonicalize)
321    }
322}
323
324impl<'a, T> ::core::iter::IntoIterator for Reader<'a, T>
325where
326    T: PrimitiveElement,
327{
328    type Item = T;
329    type IntoIter = ListIter<Reader<'a, T>, Self::Item>;
330
331    fn into_iter(self) -> Self::IntoIter {
332        self.iter()
333    }
334}
335
336impl<'a, T: PrimitiveElement + crate::introspect::Introspect> From<Reader<'a, T>>
337    for crate::dynamic_value::Reader<'a>
338{
339    fn from(t: Reader<'a, T>) -> crate::dynamic_value::Reader<'a> {
340        crate::dynamic_value::Reader::List(crate::dynamic_list::Reader::new(
341            t.reader,
342            T::introspect(),
343        ))
344    }
345}
346
347impl<'a, T: PrimitiveElement + crate::introspect::Introspect>
348    crate::dynamic_value::DowncastReader<'a> for Reader<'a, T>
349{
350    fn downcast_reader(v: crate::dynamic_value::Reader<'a>) -> Self {
351        let dl: crate::dynamic_list::Reader = v.downcast();
352        assert!(dl.element_type().loose_equals(T::introspect()));
353        Reader {
354            reader: dl.reader,
355            marker: marker::PhantomData,
356        }
357    }
358}
359
360impl<'a, T: PrimitiveElement + crate::introspect::Introspect> From<Builder<'a, T>>
361    for crate::dynamic_value::Builder<'a>
362{
363    fn from(t: Builder<'a, T>) -> crate::dynamic_value::Builder<'a> {
364        crate::dynamic_value::Builder::List(crate::dynamic_list::Builder::new(
365            t.builder,
366            T::introspect(),
367        ))
368    }
369}
370
371impl<'a, T: PrimitiveElement + crate::introspect::Introspect>
372    crate::dynamic_value::DowncastBuilder<'a> for Builder<'a, T>
373{
374    fn downcast_builder(v: crate::dynamic_value::Builder<'a>) -> Self {
375        let dl: crate::dynamic_list::Builder = v.downcast();
376        assert!(dl.element_type().loose_equals(T::introspect()));
377        Builder {
378            builder: dl.builder,
379            marker: marker::PhantomData,
380        }
381    }
382}
383
384impl<T: Copy + PrimitiveElement + crate::introspect::Introspect> core::fmt::Debug
385    for Reader<'_, T>
386{
387    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
388        core::fmt::Debug::fmt(
389            &::core::convert::Into::<crate::dynamic_value::Reader<'_>>::into(*self),
390            f,
391        )
392    }
393}