blend2d/
array.rs

1//! A contiguous growable array for use with the blend2d api.
2use core::{borrow::Borrow, fmt, iter::FromIterator, marker::PhantomData, ops, ptr, slice};
3use std::io;
4
5use crate::{
6    codec::ImageCodec,
7    error::{errcode_to_result, expect_mem_err, OutOfMemory, Result},
8    util::range_to_tuple,
9    variant::WrappedBlCore,
10};
11
12/// A contiguous growable array for use with the blend2d api.
13/// This is an array managed by blend2d, unless required one should use [`Vec`] instead.
14/// Its api tries to mimic [`Vec`] as close as possible.
15///
16/// [`String`]: std/vec/struct.Vec.html
17#[repr(transparent)]
18pub struct Array<T: ArrayType> {
19    core: ffi::BLArrayCore,
20    _pd: PhantomData<T>,
21}
22
23unsafe impl<T: ArrayType> WrappedBlCore for Array<T> {
24    type Core = ffi::BLArrayCore;
25    const IMPL_TYPE_INDEX: usize = T::IMPL_IDX;
26
27    #[inline]
28    fn from_core(core: Self::Core) -> Self {
29        Array {
30            core,
31            _pd: PhantomData,
32        }
33    }
34}
35
36impl<T: ArrayType> Array<T> {
37    /// Creates a new empty array.
38    pub fn new() -> Self {
39        Self::from_core(*Self::none())
40    }
41
42    /// Creates a new empty array with space for `cap` elements.
43    pub fn with_capacity(cap: usize) -> Self {
44        let mut this = Array::from_core(*Self::none());
45        this.reserve(cap);
46        this
47    }
48
49    /// Clears the array and its contents.
50    #[inline]
51    pub fn clear(&mut self) {
52        unsafe { ffi::blArrayClear(self.core_mut()) };
53    }
54
55    /// Shrinks the arrays allocated capacity down to its currently used size.
56    #[inline]
57    pub fn shrink_to_fit(&mut self) {
58        unsafe { expect_mem_err(ffi::blArrayShrink(self.core_mut())) };
59    }
60
61    /// Reserves capacity for at least n items.
62    ///
63    /// # Panics
64    ///
65    /// Panics if blend2d returns an
66    /// [`OutOfMemory`](../error/enum.Error.html#variant.OutOfMemory) error
67    #[inline]
68    pub fn reserve(&mut self, n: usize) {
69        self.try_reserve(n).expect("memory allocation failed");
70    }
71
72    /// Reserves capacity for at least n items.
73    #[inline]
74    pub fn try_reserve(&mut self, n: usize) -> std::result::Result<(), OutOfMemory> {
75        unsafe { OutOfMemory::from_errcode(ffi::blArrayReserve(self.core_mut(), n)) }
76    }
77
78    /// Truncates the array down to n elements.
79    #[inline]
80    pub fn truncate(&mut self, n: usize) {
81        unsafe {
82            expect_mem_err(ffi::blArrayResize(
83                self.core_mut(),
84                n.min(self.len()),
85                ptr::null(),
86            ))
87        };
88    }
89
90    /// Resizes the array so that its len is equal to `n`, filling any new items
91    /// with `fill`.
92    #[inline]
93    pub fn resize(&mut self, n: usize, fill: T)
94    where
95        T: Clone,
96    {
97        unsafe {
98            let diff = n.checked_sub(self.len()).unwrap_or_default();
99            let buff = vec![fill; diff];
100            expect_mem_err(ffi::blArrayResize(
101                self.core_mut(),
102                n,
103                buff.as_ptr() as *const _,
104            ))
105        };
106    }
107
108    /// Removes the element at the given index.
109    #[inline]
110    pub fn remove(&mut self, index: usize) -> Result<()> {
111        unsafe { errcode_to_result(ffi::blArrayRemoveIndex(self.core_mut(), index)) }
112    }
113
114    /// Removes the elements whose indices reside inside of the range
115    #[inline]
116    pub fn remove_range<R: ops::RangeBounds<usize>>(&mut self, range: R) -> Result<()> {
117        let (start, end) = range_to_tuple(range, || self.len());
118        unsafe { errcode_to_result(ffi::blArrayRemoveRange(self.core_mut(), start, end)) }
119    }
120
121    /// Returns the array as a slice.
122    #[inline]
123    pub fn as_slice(&self) -> &[T] {
124        self
125    }
126
127    /// Returns the length of the array.
128    #[inline]
129    pub fn len(&self) -> usize {
130        unsafe { ffi::blArrayGetSize(self.core()) }
131    }
132
133    /// Returns true if this array has no elements.
134    #[inline]
135    pub fn is_empty(&self) -> bool {
136        self.len() == 0
137    }
138
139    /// Returns the current capacity of the array.
140    #[inline]
141    pub fn capacity(&self) -> usize {
142        self.impl_().capacity as usize
143    }
144
145    #[inline]
146    fn data_ptr(&self) -> *const T {
147        unsafe { ffi::blArrayGetData(self.core()) as *const _ }
148    }
149}
150
151impl<T> Array<T>
152where
153    T: ArrayType + Clone,
154{
155    /// Appends all items in the slice to the array.
156    #[inline]
157    pub fn extend_from_slice<S: AsRef<[T]>>(&mut self, data: S) {
158        unsafe {
159            expect_mem_err(ffi::blArrayAppendView(
160                self.core_mut(),
161                data.as_ref().as_ptr() as *const _,
162                data.as_ref().len(),
163            ))
164        };
165    }
166
167    /// Inserts all items in the slice into the array at the given index.
168    #[inline]
169    pub fn insert_from_slice<S: AsRef<[T]>>(&mut self, index: usize, data: S) {
170        unsafe {
171            expect_mem_err(ffi::blArrayInsertView(
172                self.core_mut(),
173                index,
174                data.as_ref().as_ptr() as *const _,
175                data.as_ref().len(),
176            ))
177        };
178    }
179
180    /// Replaces the elements specified by the range of indices with the given
181    /// slice.
182    #[inline]
183    pub fn replace_from_slice<R, S>(&mut self, range: R, data: S)
184    where
185        R: ops::RangeBounds<usize>,
186        S: AsRef<[T]>,
187    {
188        let (start, end) = range_to_tuple(range, || self.len());
189        unsafe {
190            expect_mem_err(ffi::blArrayReplaceView(
191                self.core_mut(),
192                start,
193                end,
194                data.as_ref().as_ptr() as *const _,
195                data.as_ref().len(),
196            ))
197        };
198    }
199}
200
201impl<T: ArrayType> Extend<T> for Array<T> {
202    fn extend<I>(&mut self, iter: I)
203    where
204        I: IntoIterator<Item = T>,
205    {
206        for item in iter {
207            self.push(item);
208        }
209    }
210}
211
212impl<T: ArrayType> FromIterator<T> for Array<T> {
213    fn from_iter<I>(iter: I) -> Array<T>
214    where
215        I: IntoIterator<Item = T>,
216    {
217        let iter = iter.into_iter();
218        let len = iter.size_hint().1.unwrap_or(iter.size_hint().0);
219        let mut this = Self::with_capacity(len);
220        this.extend(iter);
221        this
222    }
223}
224
225impl<T: ArrayType + Clone> From<Vec<T>> for Array<T> {
226    fn from(v: Vec<T>) -> Self {
227        let mut this = Self::with_capacity(v.len());
228        this.extend_from_slice(&v);
229        this
230    }
231}
232
233impl<'a, T> From<&'a [T]> for Array<T>
234where
235    T: ArrayType + Clone,
236{
237    fn from(v: &[T]) -> Self {
238        let mut this = Self::with_capacity(v.len());
239        this.extend_from_slice(v);
240        this
241    }
242}
243
244impl io::Write for Array<u8> {
245    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
246        self.extend_from_slice(buf);
247        Ok(buf.len())
248    }
249
250    fn flush(&mut self) -> io::Result<()> {
251        Ok(())
252    }
253}
254
255impl<T: ArrayType> AsRef<[T]> for Array<T> {
256    #[inline]
257    fn as_ref(&self) -> &[T] {
258        self
259    }
260}
261
262impl<T: ArrayType> AsMut<[T]> for Array<T> {
263    #[inline]
264    fn as_mut(&mut self) -> &mut [T] {
265        self
266    }
267}
268
269impl<T: ArrayType> Borrow<[T]> for Array<T> {
270    #[inline]
271    fn borrow(&self) -> &[T] {
272        self
273    }
274}
275
276impl<T: ArrayType> ops::Deref for Array<T> {
277    type Target = [T];
278
279    #[inline]
280    fn deref(&self) -> &Self::Target {
281        unsafe { slice::from_raw_parts(self.data_ptr(), self.len()) }
282    }
283}
284
285impl<T: ArrayType> ops::DerefMut for Array<T> {
286    #[inline]
287    fn deref_mut(&mut self) -> &mut Self::Target {
288        unsafe {
289            let mut data_ptr = ptr::null_mut();
290            expect_mem_err(ffi::blArrayMakeMutable(self.core_mut(), &mut data_ptr));
291            slice::from_raw_parts_mut(data_ptr as _, self.len())
292        }
293    }
294}
295
296impl<T, I> ops::Index<I> for Array<T>
297where
298    T: ArrayType,
299    I: slice::SliceIndex<[T]>,
300{
301    type Output = I::Output;
302
303    #[inline]
304    fn index(&self, index: I) -> &Self::Output {
305        ops::Index::index(&**self, index)
306    }
307}
308
309impl<'a, T: ArrayType> IntoIterator for &'a Array<T> {
310    type Item = &'a T;
311    type IntoIter = slice::Iter<'a, T>;
312    fn into_iter(self) -> Self::IntoIter {
313        self.iter()
314    }
315}
316
317impl<T: ArrayType> Default for Array<T> {
318    #[inline]
319    fn default() -> Self {
320        Self::new()
321    }
322}
323
324impl<T: ArrayType> PartialEq for Array<T> {
325    #[inline]
326    fn eq(&self, other: &Self) -> bool {
327        unsafe { ffi::blArrayEquals(self.core(), other.core()) }
328    }
329}
330
331impl<T: ArrayType> Clone for Array<T> {
332    fn clone(&self) -> Self {
333        Self::from_core(self.init_weak())
334    }
335}
336
337impl<T> fmt::Debug for Array<T>
338where
339    T: ArrayType + fmt::Debug,
340{
341    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342        write!(f, "{:?}", self.as_ref())
343    }
344}
345
346impl<T: ArrayType> Drop for Array<T> {
347    fn drop(&mut self) {
348        unsafe { ffi::blArrayReset(&mut self.core) };
349    }
350}
351
352impl<T> Array<T>
353where
354    T: ArrayType,
355{
356    #[inline]
357    pub fn push(&mut self, item: T) {
358        unsafe { T::push(self.core_mut(), item) };
359    }
360    #[inline]
361    pub fn insert(&mut self, index: usize, item: T) {
362        unsafe { T::insert(self.core_mut(), index, item) };
363    }
364    #[inline]
365    pub fn replace(&mut self, index: usize, item: T) {
366        unsafe { T::replace(self.core_mut(), index, item) };
367    }
368}
369
370impl Array<ImageCodec> {
371    /// Searches for an image codec in the array by the given name.
372    #[inline]
373    pub fn find_codec_by_name(&self, name: &str) -> Option<&ImageCodec> {
374        self.iter().find(|c| c.name() == name)
375    }
376
377    /// Searches for an image codec in the array by the given data.
378    #[inline]
379    pub fn find_codec_by_data<R: AsRef<[u8]>>(&self, data: R) -> Option<&ImageCodec> {
380        self.into_iter()
381            .max_by_key(|codec| codec.inspect_data(data.as_ref()))
382    }
383}
384
385use crate::variant::ImplType;
386
387/// A marker trait for types that can be used for a blend2d [`Array`].
388/// This trait is also implemented for all blend2d core types.
389///
390/// [`Array`]: ./struct.Array.html
391pub trait ArrayType: Sized {
392    #[doc(hidden)]
393    const IMPL_IDX: usize;
394    #[doc(hidden)]
395    #[inline]
396    unsafe fn push(core: &mut ffi::BLArrayCore, item: Self) {
397        expect_mem_err(ffi::blArrayAppendItem(core, &item as *const _ as *const _));
398    }
399    #[doc(hidden)]
400    #[inline]
401    unsafe fn insert(core: &mut ffi::BLArrayCore, index: usize, item: Self) {
402        expect_mem_err(ffi::blArrayInsertItem(
403            core,
404            index,
405            &item as *const _ as *const _,
406        ));
407    }
408    #[doc(hidden)]
409    #[inline]
410    unsafe fn replace(core: &mut ffi::BLArrayCore, index: usize, item: Self) {
411        expect_mem_err(ffi::blArrayReplaceItem(
412            core,
413            index,
414            &item as *const _ as *const _,
415        ));
416    }
417}
418
419#[doc(hidden)]
420impl<T> ArrayType for T
421where
422    T: WrappedBlCore,
423{
424    const IMPL_IDX: usize = ImplType::ArrayVar as usize;
425    #[inline]
426    unsafe fn push(core: &mut ffi::BLArrayCore, item: Self) {
427        expect_mem_err(ffi::blArrayAppendItem(
428            core,
429            item.core() as *const _ as *const _,
430        ));
431    }
432    #[inline]
433    unsafe fn insert(core: &mut ffi::BLArrayCore, index: usize, item: Self) {
434        expect_mem_err(ffi::blArrayInsertItem(
435            core,
436            index,
437            item.core() as *const _ as *const _,
438        ));
439    }
440    #[inline]
441    unsafe fn replace(core: &mut ffi::BLArrayCore, index: usize, item: Self) {
442        expect_mem_err(ffi::blArrayReplaceItem(
443            core,
444            index,
445            item.core() as *const _ as *const _,
446        ));
447    }
448}
449
450impl<T> ArrayType for *const T {
451    const IMPL_IDX: usize = usize::IMPL_IDX;
452    #[inline]
453    unsafe fn push(core: &mut ffi::BLArrayCore, item: Self) {
454        usize::push(core, item as usize);
455    }
456    #[inline]
457    unsafe fn insert(core: &mut ffi::BLArrayCore, index: usize, item: Self) {
458        usize::insert(core, index, item as usize);
459    }
460    #[inline]
461    unsafe fn replace(core: &mut ffi::BLArrayCore, index: usize, item: Self) {
462        usize::insert(core, index, item as usize);
463    }
464}
465
466impl<T> ArrayType for *mut T {
467    const IMPL_IDX: usize = usize::IMPL_IDX;
468    #[inline]
469    unsafe fn push(core: &mut ffi::BLArrayCore, item: Self) {
470        usize::push(core, item as usize);
471    }
472    #[inline]
473    unsafe fn insert(core: &mut ffi::BLArrayCore, index: usize, item: Self) {
474        usize::insert(core, index, item as usize);
475    }
476    #[inline]
477    unsafe fn replace(core: &mut ffi::BLArrayCore, index: usize, item: Self) {
478        usize::insert(core, index, item as usize);
479    }
480}
481
482// Macro-zone ahead, you have been warned
483
484macro_rules! impl_array_type {
485    ($( $append:ident, $insert:ident, $replace:ident for $( ($ty:ty = $idx:expr) ),+);*$(;)*) => {
486        $(
487            $(
488                impl ArrayType for $ty {
489                    const IMPL_IDX: usize = $idx as usize;
490                    #[inline]
491                    unsafe fn push(core: &mut ffi::BLArrayCore, item: Self) {
492                        expect_mem_err(ffi::$append(core, item as _))
493                    }
494                    #[inline]
495                    unsafe fn insert(core: &mut ffi::BLArrayCore, index: usize, item: Self) {
496                        expect_mem_err(ffi::$insert(core, index, item as _))
497                    }
498                    #[inline]
499                    unsafe fn replace(core: &mut ffi::BLArrayCore, index: usize, item: Self) {
500                        expect_mem_err(ffi::$replace(core, index, item as _))
501                    }
502                }
503            )+
504        )*
505    };
506    ($( ( $( $ty:ty ),+ = $idx:expr) );* $(;)*) => {
507        $(
508            $(
509                impl ArrayType for $ty {
510                    const IMPL_IDX: usize = $idx as usize;
511                }
512            )+
513        )*
514    }
515}
516
517impl_array_type! {
518    blArrayAppendU8,  blArrayInsertU8,  blArrayInsertU8  for (i8  = ImplType::ArrayI8),  (u8  = ImplType::ArrayU8);
519    blArrayAppendU16, blArrayInsertU16, blArrayInsertU16 for (i16 = ImplType::ArrayI16), (u16 = ImplType::ArrayU16);
520    blArrayAppendU32, blArrayInsertU32, blArrayInsertU32 for (i32 = ImplType::ArrayI32), (u32 = ImplType::ArrayU32);
521    blArrayAppendU64, blArrayInsertU64, blArrayInsertU64 for (i64 = ImplType::ArrayI64), (u64 = ImplType::ArrayU64);
522    blArrayAppendF32, blArrayInsertF32, blArrayInsertF32 for (f32 = ImplType::ArrayF32);
523    blArrayAppendF64, blArrayInsertF64, blArrayInsertF64 for (f64 = ImplType::ArrayF32);
524}
525
526#[cfg(target_pointer_width = "32")]
527impl_array_type!(blArrayAppendU32, blArrayInsertU32, blArrayInsertU32 for (isize = ImplType::ArrayI32), (usize = ImplType::ArrayU32));
528#[cfg(target_pointer_width = "64")]
529impl_array_type!(blArrayAppendU64, blArrayInsertU64, blArrayInsertU64 for (isize = ImplType::ArrayI64), (usize = ImplType::ArrayU64));
530
531mod scope {
532    use crate::{array::ArrayType, font_defs::*, geometry::*, variant::ImplType, Tag};
533    impl_array_type! {
534        (Tag = ImplType::ArrayStruct4);
535        (PointD, PointI, SizeD, SizeI, FontFeature, FontVariation = ImplType::ArrayStruct8);
536        (Circle = ImplType::ArrayStruct12);
537        (BoxD, BoxI, Ellipse, Line, RectD, RectI = ImplType::ArrayStruct16);
538        (Arc, Chord, Pie, RoundRect, Triangle = ImplType::ArrayStruct24);
539    }
540}
541
542#[cfg(test)]
543mod test_array {
544    use crate::{array::Array, image::Image, path::Path};
545
546    #[test]
547    fn test_array_resize() {
548        let mut arr = Array::<i32>::new();
549        arr.resize(10, 32);
550        assert_eq!(&[32; 10][..], &*arr);
551
552        let mut path = Path::new();
553        path.move_to(1.0, 2.0);
554        let mut arr = Array::<Path>::new();
555        arr.resize(10, path.clone());
556        assert_eq!(&vec![path; 10][..], &*arr);
557    }
558
559    #[test]
560    fn test_array_ops_prim() {
561        let mut arr = Array::<i32>::new();
562        arr.push(32);
563        arr.push(24);
564        arr.push(16);
565        arr.push(8);
566        arr.remove(2).unwrap();
567        arr.insert(1, 0);
568        assert_eq!(&[32, 0, 24, 8], &*arr);
569    }
570
571    #[test]
572    fn test_array_ops_objects() {
573        let img = [
574            Image::new(1, 1, Default::default()).unwrap(),
575            Image::new(2, 2, Default::default()).unwrap(),
576            Image::new(3, 3, Default::default()).unwrap(),
577            Image::new(4, 4, Default::default()).unwrap(),
578            Image::new(5, 5, Default::default()).unwrap(),
579        ];
580        let mut arr = Array::<Image>::new();
581        for img in img.iter().take(4) {
582            arr.push(img.clone());
583        }
584        arr.remove(2).unwrap();
585        arr.insert(1, img[4].clone());
586        assert_eq!(
587            &[
588                img[0].clone(),
589                img[4].clone(),
590                img[1].clone(),
591                img[3].clone()
592            ][..],
593            &*arr
594        );
595    }
596
597    #[test]
598    fn test_array_deref_mut() {
599        let data = [0, 1, 2, 3, 4, 5];
600        let mut arr = Array::<i32>::from(&data[..]);
601        assert_eq!(&data, &*arr);
602        for i in 0..data.len() / 2 {
603            arr.swap(i, data.len() - 1 - i);
604        }
605        assert_eq!(&[5, 4, 3, 2, 1, 0], &*arr);
606    }
607}