skia_safe/interop/
stream.rs1use crate::{Data, prelude::*};
7use skia_bindings::{
8 self as sb, SkDynamicMemoryWStream, SkMemoryStream, SkStream, SkStreamAsset, SkWStream,
9};
10use std::{ffi, fmt, io, marker::PhantomData, mem, pin::Pin, ptr};
11
12#[repr(transparent)]
14pub struct Stream<N: NativeStreamBase>(ptr::NonNull<N>);
15unsafe impl<N: NativeStreamBase> Send for Stream<N> {}
16
17pub trait NativeStreamBase {
18 fn as_stream_mut(&mut self) -> &mut SkStream;
19}
20
21impl<T: NativeStreamBase> Drop for Stream<T> {
22 fn drop(&mut self) {
23 unsafe {
24 sb::C_SkStream_delete(self.0.as_ptr() as *mut _);
25 }
26 }
27}
28
29impl<N: NativeStreamBase> Stream<N> {
30 pub fn from_ptr(ptr: *mut N) -> Option<Stream<N>> {
31 ptr::NonNull::new(ptr).map(Stream)
32 }
33}
34
35pub type StreamAsset = Stream<SkStreamAsset>;
36impl NativeBase<SkStream> for SkStreamAsset {}
37
38impl NativeStreamBase for SkStreamAsset {
39 fn as_stream_mut(&mut self) -> &mut SkStream {
40 self.base_mut()
41 }
42}
43
44impl NativeAccess for StreamAsset {
45 type Native = SkStreamAsset;
46
47 fn native(&self) -> &SkStreamAsset {
48 unsafe { self.0.as_ref() }
49 }
50 fn native_mut(&mut self) -> &mut SkStreamAsset {
51 unsafe { self.0.as_mut() }
52 }
53}
54
55impl fmt::Debug for StreamAsset {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 f.debug_struct("StreamAsset").finish()
58 }
59}
60
61#[repr(C)]
62pub struct MemoryStream<'a> {
63 native: ptr::NonNull<SkMemoryStream>,
64 pd: PhantomData<&'a ()>,
65}
66unsafe impl Send for MemoryStream<'_> {}
67impl NativeBase<SkStream> for SkMemoryStream {}
68
69impl NativeStreamBase for SkMemoryStream {
70 fn as_stream_mut(&mut self) -> &mut SkStream {
71 self.base_mut()
72 }
73}
74
75impl Drop for MemoryStream<'_> {
76 fn drop(&mut self) {
77 unsafe {
78 sb::C_SkStream_delete(self.native_mut().as_stream_mut());
79 }
80 }
81}
82
83impl NativeAccess for MemoryStream<'_> {
84 type Native = SkMemoryStream;
85
86 fn native(&self) -> &SkMemoryStream {
87 unsafe { self.native.as_ref() }
88 }
89 fn native_mut(&mut self) -> &mut SkMemoryStream {
90 unsafe { self.native.as_mut() }
91 }
92}
93
94impl fmt::Debug for MemoryStream<'_> {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 f.debug_struct("MemoryStream")
97 .field("offset", &self.native().fOffset)
98 .finish()
99 }
100}
101
102impl MemoryStream<'_> {
103 #[allow(unused)]
105 pub fn from_bytes(bytes: &[u8]) -> MemoryStream {
106 let ptr = unsafe { sb::C_SkMemoryStream_MakeDirect(bytes.as_ptr() as _, bytes.len()) };
107
108 MemoryStream {
109 native: ptr::NonNull::new(ptr).unwrap(),
110 pd: PhantomData,
111 }
112 }
113}
114
115pub type DynamicMemoryWStream = Handle<SkDynamicMemoryWStream>;
116
117impl NativeBase<SkWStream> for SkDynamicMemoryWStream {}
118
119impl NativeDrop for SkDynamicMemoryWStream {
120 fn drop(&mut self) {
121 unsafe {
122 sb::C_SkWStream_destruct(self.base_mut());
123 }
124 }
125}
126
127impl fmt::Debug for DynamicMemoryWStream {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 f.debug_struct("DynamicMemoryWStream")
130 .field(
131 "bytes_written_before_tail",
132 &self.native().fBytesWrittenBeforeTail,
133 )
134 .finish()
135 }
136}
137
138impl DynamicMemoryWStream {
139 pub fn new() -> Self {
140 Self::construct(|w_stream| unsafe { sb::C_SkDynamicMemoryWStream_Construct(w_stream) })
141 }
142
143 pub fn from_bytes(bytes: &[u8]) -> Self {
144 let mut stream = Self::new();
145 stream.write(bytes);
146 stream
147 }
148
149 pub fn write(&mut self, bytes: &[u8]) -> bool {
150 unsafe {
151 sb::C_SkWStream_write(
152 self.native_mut().base_mut(),
153 bytes.as_ptr() as _,
154 bytes.len(),
155 )
156 }
157 }
158
159 pub fn detach_as_data(&mut self) -> Data {
160 Data::from_ptr(unsafe { sb::C_SkDynamicMemoryWStream_detachAsData(self.native_mut()) })
161 .unwrap()
162 }
163
164 pub fn detach_as_stream(&mut self) -> StreamAsset {
165 StreamAsset::from_ptr(unsafe {
166 sb::C_SkDynamicMemoryWStream_detachAsStream(self.native_mut())
167 })
168 .unwrap()
169 }
170}
171
172#[allow(unused)]
173pub struct RustStream<'a> {
174 inner: RefHandle<sb::RustStream>,
176 _phantom: PhantomData<&'a mut ()>,
177}
178
179#[allow(unused)]
180impl RustStream<'_> {
181 pub fn stream_mut(&mut self) -> &mut SkStream {
182 self.inner.native_mut().base_mut()
183 }
184
185 pub fn into_native(mut self) -> *mut SkStream {
186 let stream = self.inner.native_mut().base_mut() as *mut _;
187 mem::forget(self.inner);
188 stream
189 }
190}
191
192impl NativeBase<SkStream> for sb::RustStream {}
193
194impl NativeDrop for sb::RustStream {
195 fn drop(&mut self) {
196 unsafe { sb::C_RustStream_delete(self) }
197 }
198}
199
200#[allow(unused)]
201impl<'a> RustStream<'a> {
202 pub fn new_seekable<T: io::Read + io::Seek>(val: &'a mut T) -> Self {
203 Self {
204 inner: RefHandle::from_ptr(unsafe {
205 sb::C_RustStream_new(
206 val as *mut T as *mut ffi::c_void,
207 usize::MAX,
208 Some(read_trampoline::<T>),
209 Some(seek_start_trampoline::<T>),
210 Some(seek_current_trampoline::<T>),
211 )
212 })
213 .unwrap(),
214 _phantom: PhantomData,
215 }
216 }
217
218 pub fn new<T: io::Read>(val: &'a mut T) -> Self {
219 Self {
220 inner: RefHandle::from_ptr(unsafe {
221 sb::C_RustStream_new(
222 val as *mut T as *mut ffi::c_void,
223 usize::MAX,
224 Some(read_trampoline::<T>),
225 None,
226 None,
227 )
228 })
229 .unwrap(),
230 _phantom: PhantomData,
231 }
232 }
233}
234
235unsafe extern "C" fn read_trampoline<T>(
236 val: *mut ffi::c_void,
237 buf: *mut ffi::c_void,
238 count: usize,
239) -> usize
240where
241 T: io::Read,
242{
243 unsafe {
244 let val: &mut T = &mut *(val as *mut _);
245
246 if buf.is_null() {
247 const BUF_SIZE: usize = 128;
248
249 let mut buf = [0; BUF_SIZE];
250
251 let mut out_bytes = 0;
252 let mut count = count;
253
254 let mut val = std::panic::AssertUnwindSafe(val);
256
257 let reader = move || {
258 while count > 0 {
259 let bytes = match val.read(&mut buf[..count.min(BUF_SIZE)]) {
260 Ok(0) => break,
261 Ok(bytes) => bytes,
262 Err(_) => 0,
263 };
264
265 count -= bytes;
266 out_bytes += bytes;
267 }
268
269 out_bytes
270 };
271
272 match std::panic::catch_unwind(reader) {
273 Ok(res) => res,
274 Err(_) => {
275 println!("Panic in FFI callback for `SkStream::read`");
276 std::process::abort();
277 }
278 }
279 } else {
280 let buf: &mut [u8] = std::slice::from_raw_parts_mut(buf as _, count as _);
281
282 val.read(buf).unwrap_or(0)
283 }
284 }
285}
286
287unsafe extern "C" fn seek_start_trampoline<T: io::Seek>(val: *mut ffi::c_void, pos: usize) -> bool {
288 unsafe {
289 let val: &mut T = &mut *(val as *mut _);
290
291 let mut val = std::panic::AssertUnwindSafe(val);
294
295 match std::panic::catch_unwind(move || val.seek(io::SeekFrom::Start(pos as _))) {
296 Ok(res) => res.is_ok(),
297 Err(_) => {
298 println!("Panic in FFI callback for `SkStream::start`");
299 std::process::abort();
300 }
301 }
302 }
303}
304
305unsafe extern "C" fn seek_current_trampoline<T: io::Seek>(
306 val: *mut ffi::c_void,
307 offset: ffi::c_long,
308) -> bool {
309 unsafe {
310 let val: &mut T = &mut *(val as *mut _);
311
312 let mut val = std::panic::AssertUnwindSafe(val);
315
316 match std::panic::catch_unwind(move || val.seek(io::SeekFrom::Current(offset as _))) {
317 Ok(res) => res.is_ok(),
318 Err(_) => {
319 println!("Panic in FFI callback for `SkStream::move`");
320 std::process::abort();
321 }
322 }
323 }
324}
325
326#[allow(unused)]
327pub struct RustWStream<'a> {
328 inner: Pin<Box<Handle<sb::RustWStream>>>,
331 _phantom: PhantomData<&'a mut ()>,
332}
333
334#[allow(unused)]
335impl RustWStream<'_> {
336 pub fn stream_mut(&mut self) -> &mut SkWStream {
337 self.inner.native_mut().base_mut()
338 }
339}
340
341impl NativeBase<SkWStream> for sb::RustWStream {}
342
343impl NativeDrop for sb::RustWStream {
344 fn drop(&mut self) {
345 unsafe { sb::C_RustWStream_destruct(self) }
346 }
347}
348
349impl<'a> RustWStream<'a> {
350 pub fn new<T: io::Write>(writer: &'a mut T) -> Self {
351 return RustWStream {
352 inner: Box::pin(Handle::construct(|ptr| unsafe {
353 sb::C_RustWStream_construct(
354 ptr,
355 writer as *mut T as *mut ffi::c_void,
356 Some(write_trampoline::<T>),
357 Some(flush_trampoline::<T>),
358 );
359 })),
360 _phantom: PhantomData,
361 };
362
363 unsafe extern "C" fn write_trampoline<T: io::Write>(
364 val: *mut ffi::c_void,
365 buf: *const ffi::c_void,
366 count: usize,
367 ) -> bool {
368 unsafe {
369 if count == 0 {
370 return true;
371 }
372 let buf: &[u8] = std::slice::from_raw_parts(buf as _, count as _);
373 let val: &mut T = &mut *(val as *mut _);
374
375 let mut val = std::panic::AssertUnwindSafe(val);
377
378 let writer = move || {
379 let mut written = 0;
380 while written != count {
381 match val.write(&buf[written..]) {
382 Ok(res) if res != 0 => {
383 written += res;
384 }
385 _ => return false,
386 }
387 }
388 true
389 };
390
391 match std::panic::catch_unwind(writer) {
392 Ok(res) => res,
393 Err(_) => {
394 println!("Panic in FFI callback for `SkWStream::write`");
395 std::process::abort();
396 }
397 }
398 }
399 }
400
401 unsafe extern "C" fn flush_trampoline<T: io::Write>(val: *mut ffi::c_void) {
402 unsafe {
403 let val: &mut T = &mut *(val as *mut _);
404 let mut val = std::panic::AssertUnwindSafe(val);
406
407 let flusher = move || {
408 let _flush_result_ignored = val.flush();
412 };
413
414 match std::panic::catch_unwind(flusher) {
415 Ok(_) => {}
416 Err(_) => {
417 println!("Panic in FFI callback for `SkWStream::flush`");
418 std::process::abort();
419 }
420 }
421 }
422 }
423 }
424}
425
426#[cfg(test)]
427mod tests {
428 use super::{MemoryStream, RustStream};
429 use crate::interop::DynamicMemoryWStream;
430
431 #[test]
432 fn detaching_empty_dynamic_memory_w_stream_leads_to_non_null_data() {
433 let mut stream = DynamicMemoryWStream::new();
434 let data = stream.detach_as_data();
435 assert_eq!(0, data.size())
436 }
437
438 #[test]
439 fn memory_stream_from_bytes() {
440 let stream = MemoryStream::from_bytes(&[1, 2, 3]);
441 drop(stream);
442 }
443
444 #[test]
445 fn read_from_rust_stream() {
446 let mut data: &[u8] = &[12u8, 13u8, 14u8];
447 let mut stream = RustStream::new(&mut data);
448
449 let mut first_byte = 0i8;
450 unsafe {
451 stream.stream_mut().readS8(&mut first_byte);
452 }
453 assert_eq!(first_byte, 12i8)
454 }
455}