clap_clap/stream.rs
1//! CLAP I/O streams for storing and loading plugin state.
2//!
3//! # Notes on using streams
4//!
5//! When working with `IStream` and `OStream` objects to load and save
6//! state, it is important to keep in mind that the host may limit the number of
7//! bytes that can be read or written at a time. The return values for the
8//! stream read and write functions indicate how many bytes were actually read
9//! or written. You need to use a loop to ensure that you read or write the
10//! entirety of your state. Don't forget to also consider the negative return
11//! values for the end of file and IO error codes.
12
13use std::{
14 ffi::c_void,
15 io::{Read, Write},
16};
17
18use crate::ffi::{clap_istream, clap_ostream};
19
20#[derive(Debug)]
21pub struct IStream(*const clap_istream);
22
23impl IStream {
24 /// # Safety
25 ///
26 /// The pointer to `clap_istream` must be non-null and must point to a valid
27 /// input stream handle provided by the host. In particular, the function
28 /// pointer clap_istream.read must be non-null.
29 #[doc(hidden)]
30 pub const unsafe fn new_unchecked(clap_istream: *const clap_istream) -> Self {
31 Self(clap_istream)
32 }
33
34 #[doc(hidden)]
35 pub const fn clap_istream(&self) -> &clap_istream {
36 // SAFETY: By construction, the pointer is non-null and points to a valid
37 // clap_istream instance.
38 unsafe { self.0.as_ref().unwrap() }
39 }
40}
41
42impl Read for IStream {
43 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
44 let size = buf.len() as u64;
45 let buffer = buf.as_mut_ptr() as *mut c_void;
46
47 // SAFETY: The pointer to `read` method is non-null and safe to call by
48 // construction.
49 let n = unsafe { self.clap_istream().read.unwrap()(self.0, buffer, size) };
50
51 if n >= 0 {
52 Ok(n as usize)
53 } else {
54 Err(std::io::Error::other("read error"))
55 }
56 }
57}
58
59#[derive(Debug)]
60pub struct OStream(*const clap_ostream);
61
62impl OStream {
63 /// # Safety
64 ///
65 /// The pointer to `clap_ostream` must be non-null and must point to a valid
66 /// input stream handle provided by the host. In particular, the function
67 /// pointer clap_ostream.write must be non-null.
68 #[doc(hidden)]
69 pub const unsafe fn new_unchecked(clap_ostream: *const clap_ostream) -> Self {
70 Self(clap_ostream)
71 }
72
73 #[doc(hidden)]
74 pub const fn clap_ostream(&self) -> &clap_ostream {
75 // SAFETY: By construction, the pointer is non-null and points to a valid
76 // clap_ostream instance.
77 unsafe { self.0.as_ref().unwrap() }
78 }
79}
80
81impl Write for OStream {
82 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
83 let size = buf.len() as u64;
84 let buffer = buf.as_ptr() as *mut c_void;
85
86 // SAFETY: The pointer to `write` method is non-null and safe to call by
87 // construction.
88 let n = unsafe { self.clap_ostream().write.unwrap()(self.0, buffer, size) };
89 if n >= 0 {
90 Ok(n as usize)
91 } else {
92 Err(std::io::Error::other("write error"))
93 }
94 }
95
96 fn flush(&mut self) -> std::io::Result<()> {
97 Ok(())
98 }
99}