hapi_rs/attribute/
array.rs

1use crate::errors::Result;
2use crate::stringhandle::{StringArray, StringHandle};
3use std::borrow::Cow;
4
5/// Groups _data_ and _sizes_ arrays for working with geometry attributes.
6/// See [`crate::attribute::NumericArrayAttr::get`].
7pub struct DataArray<'a, T>
8where
9    [T]: ToOwned<Owned = Vec<T>>,
10{
11    data: Cow<'a, [T]>,
12    sizes: Cow<'a, [i32]>,
13}
14impl<'a, T> DataArray<'a, T>
15where
16    [T]: ToOwned<Owned = Vec<T>>,
17{
18    /// Create a new data array
19    pub fn new(data: &'a [T], sizes: &'a [i32]) -> DataArray<'a, T> {
20        debug_assert_eq!(sizes.iter().sum::<i32>() as usize, data.len());
21        DataArray {
22            data: Cow::Borrowed(data),
23            sizes: Cow::Borrowed(sizes),
24        }
25    }
26
27    // Owned variant returned by APIs
28    pub(crate) fn new_owned(data: Vec<T>, sizes: Vec<i32>) -> DataArray<'static, T> {
29        debug_assert_eq!(sizes.iter().sum::<i32>() as usize, data.len());
30        DataArray {
31            data: Cow::Owned(data),
32            sizes: Cow::Owned(sizes),
33        }
34    }
35
36    /// Get reference to the data buffer.
37    pub fn data(&self) -> &[T] {
38        self.data.as_ref()
39    }
40    /// Get reference to the sizes array.
41    pub fn sizes(&self) -> &[i32] {
42        self.sizes.as_ref()
43    }
44
45    pub fn data_mut(&mut self) -> &mut [T] {
46        self.data.to_mut().as_mut()
47    }
48    pub fn sizes_mut(&mut self) -> &mut [i32] {
49        self.sizes.to_mut().as_mut()
50    }
51
52    /// Create an iterator over the data .
53    pub fn iter(&'a self) -> ArrayIter<'a, T> {
54        ArrayIter {
55            sizes: self.sizes.iter(),
56            data: self.data.as_ref(),
57            cursor: 0,
58        }
59    }
60    /// Create an mutable iterator over the data .
61    pub fn iter_mut(&'a mut self) -> ArrayIterMut<'a, T> {
62        ArrayIterMut {
63            sizes: self.sizes.to_mut().iter_mut(),
64            data: self.data.to_mut().as_mut(),
65            cursor: 0,
66        }
67    }
68}
69
70/// Represents multi-array string data. Used as storage for string and dictionary array attributes.
71/// Each element of this array is itself a [`StringArray`]
72pub struct StringMultiArray {
73    pub(crate) handles: Vec<StringHandle>,
74    pub(crate) sizes: Vec<i32>,
75    pub(crate) session: crate::session::Session,
76}
77
78/// Returned by [`DataArray::iter`]
79pub struct ArrayIter<'a, T> {
80    data: &'a [T],
81    sizes: std::slice::Iter<'a, i32>,
82    cursor: usize,
83}
84
85/// Returned by [`DataArray::iter_mut`]
86pub struct ArrayIterMut<'a, T> {
87    data: &'a mut [T],
88    sizes: std::slice::IterMut<'a, i32>,
89    cursor: usize,
90}
91
92pub struct MultiArrayIter<'a> {
93    handles: std::slice::Iter<'a, StringHandle>,
94    sizes: std::slice::Iter<'a, i32>,
95    session: &'a crate::session::Session,
96    cursor: usize,
97}
98
99impl<'a, T> Iterator for ArrayIter<'a, T> {
100    type Item = &'a [T];
101
102    fn next(&mut self) -> Option<Self::Item> {
103        match self.sizes.next() {
104            None => None,
105            Some(size) => {
106                let start = self.cursor;
107                let end = self.cursor + (*size as usize);
108                self.cursor = end;
109                // SAFETY: The data and the sizes arrays are both provided by HAPI
110                // are expected to match. Also bounds are checked in debug build.
111                Some(unsafe { self.data.get_unchecked(start..end) })
112            }
113        }
114    }
115}
116
117impl<'a, T> Iterator for ArrayIterMut<'a, T> {
118    type Item = &'a mut [T];
119
120    fn next(&mut self) -> Option<Self::Item> {
121        match self.sizes.next() {
122            None => None,
123            Some(size) => {
124                let start = self.cursor;
125                let end = self.cursor + (*size as usize);
126                self.cursor = end;
127                // SAFETY: Compiler can't know that we're never return overlapping references
128                // so we "erase" the lifetime by casting to pointer and back.
129                Some(unsafe { &mut *(self.data.get_unchecked_mut(start..end) as *mut [T]) })
130            }
131        }
132    }
133}
134
135impl StringMultiArray {
136    pub fn iter(&self) -> MultiArrayIter<'_> {
137        MultiArrayIter {
138            handles: self.handles.iter(),
139            sizes: self.sizes.iter(),
140            session: &self.session,
141            cursor: 0,
142        }
143    }
144    /// Convenient method to flatten the data and the sizes multidimensional arrays into individual vectors
145    pub fn flatten(self) -> Result<(Vec<String>, Vec<usize>)> {
146        let mut flat_array = Vec::with_capacity(self.sizes.iter().sum::<i32>() as usize);
147        let mut iter = self.iter();
148        while let Some(Ok(string_array)) = iter.next() {
149            flat_array.extend(string_array.into_iter());
150        }
151        Ok((flat_array, self.sizes.iter().map(|v| *v as usize).collect()))
152    }
153}
154
155impl Iterator for MultiArrayIter<'_> {
156    type Item = Result<StringArray>;
157
158    fn next(&mut self) -> Option<Self::Item> {
159        match self.sizes.next() {
160            None => None,
161            Some(size) => {
162                let start = self.cursor;
163                let end = self.cursor + (*size as usize);
164                self.cursor = end;
165                let handles = &self.handles.as_slice()[start..end];
166                Some(crate::stringhandle::get_string_array(handles, self.session))
167            }
168        }
169    }
170}
171
172#[cfg(test)]
173mod tests {
174    use super::*;
175
176    #[test]
177    fn data_array_iter() {
178        let ar = DataArray::new_owned(vec![1, 2, 3, 4, 5, 6], vec![2, 1, 3]);
179        let mut iter = ar.iter();
180        assert_eq!(iter.next(), Some([1, 2].as_slice()));
181        assert_eq!(iter.next(), Some([3].as_slice()));
182        assert_eq!(iter.next(), Some([4, 5, 6].as_slice()));
183    }
184
185    #[test]
186    fn data_array_mutate() {
187        let mut ar = DataArray::new(&[1, 2, 3, 4, 5, 6], &[2, 1, 3]);
188        let mut iter = ar.iter_mut().map(|v| {
189            v.iter_mut().for_each(|v| *v *= 2);
190            v
191        });
192        assert_eq!(iter.next(), Some([2, 4].as_mut_slice()));
193        assert_eq!(iter.next(), Some([6].as_mut_slice()));
194        assert_eq!(iter.next(), Some([8, 10, 12].as_mut_slice()));
195    }
196}