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`]
72#[derive(Debug, Clone)]
73pub struct StringMultiArray {
74    pub(crate) handles: Vec<StringHandle>,
75    pub(crate) sizes: Vec<i32>,
76    pub(crate) session: debug_ignore::DebugIgnore<crate::session::Session>,
77}
78
79/// Returned by [`DataArray::iter`]
80pub struct ArrayIter<'a, T> {
81    data: &'a [T],
82    sizes: std::slice::Iter<'a, i32>,
83    cursor: usize,
84}
85
86/// Returned by [`DataArray::iter_mut`]
87pub struct ArrayIterMut<'a, T> {
88    data: &'a mut [T],
89    sizes: std::slice::IterMut<'a, i32>,
90    cursor: usize,
91}
92
93pub struct MultiArrayIter<'a> {
94    handles: std::slice::Iter<'a, StringHandle>,
95    sizes: std::slice::Iter<'a, i32>,
96    session: &'a crate::session::Session,
97    cursor: usize,
98}
99
100impl<'a, T> Iterator for ArrayIter<'a, T> {
101    type Item = &'a [T];
102
103    fn next(&mut self) -> Option<Self::Item> {
104        match self.sizes.next() {
105            None => None,
106            Some(size) => {
107                let start = self.cursor;
108                let end = self.cursor + (*size as usize);
109                self.cursor = end;
110                // SAFETY: The data and the sizes arrays are both provided by HAPI
111                // are expected to match. Also bounds are checked in debug build.
112                Some(unsafe { self.data.get_unchecked(start..end) })
113            }
114        }
115    }
116}
117
118impl<'a, T> Iterator for ArrayIterMut<'a, T> {
119    type Item = &'a mut [T];
120
121    fn next(&mut self) -> Option<Self::Item> {
122        match self.sizes.next() {
123            None => None,
124            Some(size) => {
125                let start = self.cursor;
126                let end = self.cursor + (*size as usize);
127                self.cursor = end;
128                // SAFETY: Compiler can't know that we're never return overlapping references
129                // so we "erase" the lifetime by casting to pointer and back.
130                Some(unsafe { &mut *(self.data.get_unchecked_mut(start..end) as *mut [T]) })
131            }
132        }
133    }
134}
135
136impl StringMultiArray {
137    pub fn iter(&self) -> MultiArrayIter<'_> {
138        MultiArrayIter {
139            handles: self.handles.iter(),
140            sizes: self.sizes.iter(),
141            session: &self.session,
142            cursor: 0,
143        }
144    }
145    /// Convenient method to flatten the data and the sizes multidimensional arrays into individual vectors
146    pub fn flatten(self) -> Result<(Vec<String>, Vec<usize>)> {
147        let mut flat_array = Vec::with_capacity(self.sizes.iter().sum::<i32>() as usize);
148        let mut iter = self.iter();
149        while let Some(Ok(string_array)) = iter.next() {
150            flat_array.extend(string_array.into_iter());
151        }
152        Ok((flat_array, self.sizes.iter().map(|v| *v as usize).collect()))
153    }
154}
155
156impl Iterator for MultiArrayIter<'_> {
157    type Item = Result<StringArray>;
158
159    fn next(&mut self) -> Option<Self::Item> {
160        match self.sizes.next() {
161            None => None,
162            Some(size) => {
163                let start = self.cursor;
164                let end = self.cursor + (*size as usize);
165                self.cursor = end;
166                let handles = &self.handles.as_slice()[start..end];
167                Some(crate::stringhandle::get_string_array(handles, self.session))
168            }
169        }
170    }
171}
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176
177    #[test]
178    fn data_array_iter() {
179        let ar = DataArray::new_owned(vec![1, 2, 3, 4, 5, 6], vec![2, 1, 3]);
180        let mut iter = ar.iter();
181        assert_eq!(iter.next(), Some([1, 2].as_slice()));
182        assert_eq!(iter.next(), Some([3].as_slice()));
183        assert_eq!(iter.next(), Some([4, 5, 6].as_slice()));
184    }
185
186    #[test]
187    fn data_array_mutate() {
188        let mut ar = DataArray::new(&[1, 2, 3, 4, 5, 6], &[2, 1, 3]);
189        let mut iter = ar.iter_mut().map(|array| {
190            array.iter_mut().for_each(|v| *v *= 2);
191            array
192        });
193        assert_eq!(iter.next(), Some([2, 4].as_mut_slice()));
194        assert_eq!(iter.next(), Some([6].as_mut_slice()));
195        assert_eq!(iter.next(), Some([8, 10, 12].as_mut_slice()));
196    }
197}