Skip to main content

ferroui_base/utilities/
array_slice.rs

1//! `ArraySlice<T>`: a view over a shared, mutable array.
2//!
3//! Upstream's `ArraySlice<T>` is a `(T[] data, int start, int length)` triple
4//! with reference semantics: several slices alias one array and writes through
5//! one are visible through the others. The Rust counterpart shares the array
6//! through `Rc<RefCell<..>>`; reads borrow the whole array once (`span()`), so
7//! loops over glyphs pay one borrow, not one per element.
8
9use std::cell::{Ref, RefCell, RefMut};
10use std::rc::Rc;
11
12/// A view over `length` elements of a shared array starting at `start`.
13pub struct ArraySlice<T> {
14    data: Rc<RefCell<Vec<T>>>,
15    start: usize,
16    length: usize,
17}
18
19impl<T> ArraySlice<T> {
20    /// An empty slice (C# `ArraySlice<T>.Empty`).
21    pub fn empty() -> Self {
22        Self { data: Rc::new(RefCell::new(Vec::new())), start: 0, length: 0 }
23    }
24
25    /// A slice over a whole new array.
26    pub fn new(data: Vec<T>) -> Self {
27        let length = data.len();
28        Self { data: Rc::new(RefCell::new(data)), start: 0, length }
29    }
30
31    /// A slice over part of a shared array.
32    ///
33    /// Panics when the range is outside the array.
34    pub fn from_shared(data: Rc<RefCell<Vec<T>>>, start: usize, length: usize) -> Self {
35        {
36            let array = data.borrow();
37            assert!(start <= array.len() && length <= array.len() - start, "range outside of the array");
38        }
39        Self { data, start, length }
40    }
41
42    /// The shared array this slice views.
43    #[inline]
44    pub fn data(&self) -> &Rc<RefCell<Vec<T>>> {
45        &self.data
46    }
47
48    /// Whether the slice has no elements.
49    #[inline]
50    pub fn is_empty(&self) -> bool {
51        self.length == 0
52    }
53
54    /// The offset of the slice inside the shared array.
55    #[inline]
56    pub fn start(&self) -> usize {
57        self.start
58    }
59
60    /// The number of elements.
61    #[inline]
62    pub fn length(&self) -> usize {
63        self.length
64    }
65
66    /// Borrows the elements (C# `Span`).
67    ///
68    /// Panics when the array is mutably borrowed.
69    #[inline]
70    pub fn span(&self) -> Ref<'_, [T]> {
71        Ref::map(self.data.borrow(), |array| &array[self.start..self.start + self.length])
72    }
73
74    /// Mutably borrows the elements (C# `Span`).
75    ///
76    /// Panics when the array is borrowed.
77    #[inline]
78    pub fn span_mut(&self) -> RefMut<'_, [T]> {
79        RefMut::map(self.data.borrow_mut(), |array| &mut array[self.start..self.start + self.length])
80    }
81
82    /// Writes one element.
83    #[inline]
84    pub fn set(&self, index: usize, value: T) {
85        self.span_mut()[index] = value;
86    }
87
88    /// A slice of the same array. As upstream, `start` is relative to the
89    /// underlying array, not to this slice.
90    pub fn slice(&self, start: usize, length: usize) -> Self {
91        Self::from_shared(self.data.clone(), start, length)
92    }
93
94    /// The first `length` elements.
95    ///
96    /// Panics when `length` is larger than the slice.
97    pub fn take(&self, length: usize) -> Self {
98        if self.is_empty() {
99            return self.clone();
100        }
101        assert!(length <= self.length, "length out of range");
102        Self { data: self.data.clone(), start: self.start, length }
103    }
104
105    /// Everything after the first `length` elements.
106    ///
107    /// Panics when `length` is larger than the slice.
108    pub fn skip(&self, length: usize) -> Self {
109        if self.is_empty() {
110            return self.clone();
111        }
112        assert!(length <= self.length, "length out of range");
113        Self { data: self.data.clone(), start: self.start + length, length: self.length - length }
114    }
115}
116
117impl<T: Copy> ArraySlice<T> {
118    /// Reads one element.
119    #[inline]
120    pub fn get(&self, index: usize) -> T {
121        self.span()[index]
122    }
123
124    /// Sets every element to `value`.
125    pub fn fill(&self, value: T) {
126        self.span_mut().fill(value);
127    }
128}
129
130impl<T> Clone for ArraySlice<T> {
131    fn clone(&self) -> Self {
132        Self { data: self.data.clone(), start: self.start, length: self.length }
133    }
134}
135
136impl<T> From<Vec<T>> for ArraySlice<T> {
137    fn from(data: Vec<T>) -> Self {
138        Self::new(data)
139    }
140}
141
142#[cfg(test)]
143mod tests {
144    use super::*;
145
146    #[test]
147    fn slices_alias_the_array() {
148        let slice = ArraySlice::new(vec![1, 2, 3, 4, 5]);
149        let tail = slice.skip(2);
150        tail.set(0, 30);
151        assert_eq!(&*slice.span(), &[1, 2, 30, 4, 5]);
152        assert_eq!(tail.start(), 2);
153        assert_eq!(tail.take(2).length(), 2);
154        // `slice` takes an absolute start, as upstream.
155        assert_eq!(&*tail.slice(1, 2).span(), &[2, 30]);
156        slice.take(2).fill(0);
157        assert_eq!(slice.get(1), 0);
158    }
159}