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}