1use std::fmt::{Display, Formatter};
2
3use crate::{
4 plugin::Plugin,
5 stream::{IStream, OStream},
6};
7
8pub trait State<P: Plugin> {
9 fn save(plugin: &P, stream: &mut OStream) -> Result<(), crate::Error>;
15
16 fn load(plugin: &P, stream: &mut IStream) -> Result<(), crate::Error>;
22}
23
24pub(crate) use ffi::PluginState;
25
26use crate::{ffi::clap_host_state, host::Host};
27
28mod ffi {
29 use std::marker::PhantomData;
30
31 use crate::{
32 ext::state::State,
33 ffi::{clap_istream, clap_ostream, clap_plugin, clap_plugin_state},
34 plugin::{ClapPlugin, Plugin},
35 stream::{IStream, OStream},
36 };
37
38 extern "C-unwind" fn save<E, P>(plugin: *const clap_plugin, stream: *const clap_ostream) -> bool
39 where
40 E: State<P>,
41 P: Plugin,
42 {
43 if plugin.is_null() {
44 return false;
45 }
46 let mut clap_plugin = unsafe { ClapPlugin::<P>::new_unchecked(plugin) };
49
50 let plugin = unsafe { clap_plugin.plugin() };
55
56 if unsafe { stream.as_ref().and_then(|s| s.write) }.is_none() {
57 return false;
58 }
59 let mut stream = unsafe { OStream::new_unchecked(stream) };
61
62 E::save(plugin, &mut stream).is_ok()
63 }
64
65 extern "C-unwind" fn load<E, P>(plugin: *const clap_plugin, stream: *const clap_istream) -> bool
66 where
67 E: State<P>,
68 P: Plugin,
69 {
70 if plugin.is_null() {
71 return false;
72 }
73 let mut clap_plugin = unsafe { ClapPlugin::<P>::new_unchecked(plugin) };
76
77 let plugin = unsafe { clap_plugin.plugin() };
82
83 if unsafe { stream.as_ref().and_then(|s| s.read) }.is_none() {
84 return false;
85 }
86 let mut stream = unsafe { IStream::new_unchecked(stream) };
88
89 E::load(plugin, &mut stream).is_ok()
90 }
91
92 pub(crate) struct PluginState<P> {
93 #[allow(unused)]
94 clap_plugin_state: clap_plugin_state,
95 _marker: PhantomData<P>,
96 }
97
98 impl<P: Plugin> PluginState<P> {
99 pub(crate) fn new<E: State<P>>(_: E) -> Self {
100 Self {
101 clap_plugin_state: clap_plugin_state {
102 save: Some(save::<E, P>),
103 load: Some(load::<E, P>),
104 },
105 _marker: PhantomData,
106 }
107 }
108 }
109}
110
111impl<P: Plugin> State<P> for () {
112 fn save(_: &P, _: &mut OStream) -> Result<(), crate::Error> {
113 Ok(())
114 }
115
116 fn load(_: &P, _: &mut IStream) -> Result<(), crate::Error> {
117 Ok(())
118 }
119}
120
121#[derive(Debug)]
122pub struct HostState<'a> {
123 host: &'a Host,
124 clap_host_state: &'a clap_host_state,
125}
126
127impl<'a> HostState<'a> {
128 pub(crate) const unsafe fn new_unchecked(
133 host: &'a Host,
134 clap_host_state: &'a clap_host_state,
135 ) -> Self {
136 Self {
137 host,
138 clap_host_state,
139 }
140 }
141
142 pub fn make_dirty(&self) {
143 let callback = self.clap_host_state.mark_dirty.unwrap();
146 unsafe { callback(self.host.clap_host()) }
147 }
148}
149
150#[derive(Debug)]
151pub enum Error {
152 Read,
153 Write,
154 Eof,
155}
156
157impl Display for Error {
158 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
159 use Error::*;
160 match self {
161 Read => write!(f, "read error"),
162 Write => write!(f, "write error"),
163 Eof => write!(f, "end of file"),
164 }
165 }
166}
167
168impl std::error::Error for Error {}
169
170impl From<Error> for crate::Error {
171 fn from(value: Error) -> Self {
172 crate::ext::Error::State(value).into()
173 }
174}