1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use std::{
ffi::c_void,
ops::{Deref, DerefMut},
ptr::{self, NonNull},
slice,
};
use mupdf_sys::fz_free;
use crate::context;
/// Essentially a [`Box`]`<[T], A>` with `fz_calloc` as the allocator. Necessary until the
/// allocator API is stable, as we need to be able to free this with `fz_free` instead of the
/// system allocator.
// An important note about `fz_calloc`: If a function which allocates from `fz_calloc` gives you a
// pointer, allocated from `fz_calloc`, but says the length of items behind it is 0, you still have
// to `fz_free` that pointer. It's probably lying about the length behind it being 0 - it was
// probably part of an allocation bigger than 0, but of which 0 bytes were actually written to.
pub struct FzArray<T> {
ptr: Option<NonNull<T>>,
len: usize,
}
impl<T> Default for FzArray<T> {
fn default() -> Self {
Self { ptr: None, len: 0 }
}
}
impl<T> FzArray<T> {
/// # Safety
///
/// * `ptr` must point to an array of at least `len` instances of `T`. There may be more than
/// `len` instances, but only `len` will be accessed by this struct.
///
/// * If `len > 0`, the memory it points to also must be allocated by `fz_calloc` inside a
/// mupdf FFI call. `ptr` may be dangling or not well-aligned if `len == 0`
pub(crate) unsafe fn from_parts(ptr: NonNull<T>, len: usize) -> Self {
Self {
ptr: Some(ptr),
len,
}
}
/// # Safety
///
/// * It must be valid to call [`FzArray::from_parts`] with the ptr stored inside `self` and
/// the `len` specified in this call
pub(crate) unsafe fn set_len(&mut self, len: usize) {
self.len = len;
}
}
impl<T> Deref for FzArray<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
match self.ptr {
// SAFETY: Constructors require `ptr` to point to at least `self.len` initialized
// contiguous `T` values for the lifetime of `self`.
Some(ptr) => unsafe { slice::from_raw_parts(ptr.as_ptr(), self.len) },
None => &[],
}
}
}
impl<T> DerefMut for FzArray<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self.ptr.as_mut() {
Some(ptr) => {
// SAFETY: Constructors require `ptr` to point to at least `self.len` initialized
// contiguous `T` values, and `&mut self` guarantees unique access.
unsafe { slice::from_raw_parts_mut(ptr.as_ptr(), self.len) }
}
None => &mut [],
}
}
}
impl<T> Drop for FzArray<T> {
fn drop(&mut self) {
if let Some(ptr) = self.ptr {
// SAFETY: Upheld by constructor - this must point to something allocated by fz_calloc
unsafe { fz_free(context(), ptr.as_ptr() as *mut c_void) };
}
}
}
impl<T> IntoIterator for FzArray<T> {
type IntoIter = FzIter<T>;
type Item = T;
fn into_iter(self) -> Self::IntoIter {
let next_item_and_end = self.ptr.map(|p| {
// Would be nice to use `.addr()` but it seems CI doesn't have 1.84 yet, and that's
// what stabilized the strict provenance APIs
let end = p.as_ptr().wrapping_add(self.len) as usize;
(p, end)
});
FzIter {
_kept_to_be_dropped: self,
next_item_and_end,
}
}
}
pub struct FzIter<T> {
_kept_to_be_dropped: FzArray<T>,
next_item_and_end: Option<(NonNull<T>, usize)>,
}
impl<T> Iterator for FzIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let (next_item, end_addr) = self.next_item_and_end.as_mut()?;
// Same thing as above with `.addr()`
if next_item.as_ptr() as usize == *end_addr {
return None;
}
// SAFETY: `next_item` points at the next not-yet-yielded element and is before `end_addr`.
let ret = unsafe { ptr::read(next_item.as_ptr()) };
// SAFETY: We have not reached `end_addr`, so advancing by one stays within or one-past the
// allocation tracked by `_kept_to_be_dropped`.
*next_item = unsafe { next_item.add(1) };
Some(ret)
}
}
// SAFETY: `FzArray<T>` has ownership semantics equivalent to `Box<[T]>` backed by MuPDF's
// allocator. Moving it to another thread is safe when `T: Send`.
unsafe impl<T> Send for FzArray<T> where T: Send {}
// SAFETY: Shared access to `FzArray<T>` only exposes shared access to its elements, so sharing
// references is safe when `T: Sync`.
unsafe impl<T> Sync for FzArray<T> where T: Sync {}