1use crate::raw::*;
2use crate::StateErr;
3use core::extension::ExtensionDescriptor;
4use core::prelude::*;
5use std::marker::PhantomData;
6use urid::*;
7
8pub trait State: Plugin {
14 type StateFeatures: FeatureCollection<'static>;
16
17 fn save(&self, store: StoreHandle, features: Self::StateFeatures) -> Result<(), StateErr>;
21
22 fn restore(
26 &mut self,
27 store: RetrieveHandle,
28 features: Self::StateFeatures,
29 ) -> Result<(), StateErr>;
30}
31
32pub struct StateDescriptor<P: State> {
36 plugin: PhantomData<P>,
37}
38
39unsafe impl<P: State> UriBound for StateDescriptor<P> {
40 const URI: &'static [u8] = sys::LV2_STATE__interface;
41}
42
43impl<P: State> StateDescriptor<P> {
44 pub unsafe extern "C" fn extern_save(
52 instance: sys::LV2_Handle,
53 store: sys::LV2_State_Store_Function,
54 handle: sys::LV2_State_Handle,
55 flags: u32,
56 features: *const *const sys::LV2_Feature,
57 ) -> sys::LV2_State_Status {
58 let flags: u32 =
59 (sys::LV2_State_Flags::from(flags) & sys::LV2_State_Flags::LV2_STATE_IS_POD).into();
60 if flags == 0 {
61 return sys::LV2_State_Status_LV2_STATE_ERR_BAD_FLAGS;
62 }
63
64 let plugin: &P = if let Some(plugin) = (instance as *const P).as_ref() {
65 plugin
66 } else {
67 return sys::LV2_State_Status_LV2_STATE_ERR_UNKNOWN;
68 };
69
70 let store = StoreHandle::new(store, handle);
71
72 let mut feature_container = core::feature::FeatureCache::from_raw(features);
73 let features = if let Ok(features) =
74 P::StateFeatures::from_cache(&mut feature_container, ThreadingClass::Other)
75 {
76 features
77 } else {
78 return sys::LV2_State_Status_LV2_STATE_ERR_NO_FEATURE;
79 };
80
81 StateErr::into(plugin.save(store, features))
82 }
83
84 pub unsafe extern "C" fn extern_restore(
92 instance: sys::LV2_Handle,
93 retrieve: sys::LV2_State_Retrieve_Function,
94 handle: sys::LV2_State_Handle,
95 flags: u32,
96 features: *const *const sys::LV2_Feature,
97 ) -> sys::LV2_State_Status {
98 let flags: u32 =
99 (sys::LV2_State_Flags::from(flags) & sys::LV2_State_Flags::LV2_STATE_IS_POD).into();
100 if flags == 0 {
101 return sys::LV2_State_Status_LV2_STATE_ERR_BAD_FLAGS;
102 }
103
104 let plugin: &mut P = if let Some(plugin) = (instance as *mut P).as_mut() {
105 plugin
106 } else {
107 return sys::LV2_State_Status_LV2_STATE_ERR_UNKNOWN;
108 };
109
110 let store = RetrieveHandle::new(retrieve, handle);
111
112 let mut feature_container = core::feature::FeatureCache::from_raw(features);
113 let features = if let Ok(features) =
114 P::StateFeatures::from_cache(&mut feature_container, ThreadingClass::Other)
115 {
116 features
117 } else {
118 return sys::LV2_State_Status_LV2_STATE_ERR_NO_FEATURE;
119 };
120
121 StateErr::into(plugin.restore(store, features))
122 }
123}
124
125impl<P: State> ExtensionDescriptor for StateDescriptor<P> {
126 type ExtensionInterface = sys::LV2_State_Interface;
127
128 const INTERFACE: &'static sys::LV2_State_Interface = &sys::LV2_State_Interface {
129 save: Some(Self::extern_save),
130 restore: Some(Self::extern_restore),
131 };
132}
133
134#[cfg(test)]
135mod tests {
136 use crate::*;
137 use lv2_core::prelude::*;
138 use lv2_urid::*;
139 use urid::*;
140
141 #[uri("urn:stateful")]
142 struct Stateful;
143
144 impl Plugin for Stateful {
145 type InitFeatures = ();
146 type AudioFeatures = ();
147 type Ports = ();
148
149 #[cfg_attr(tarpaulin, skip)]
150 fn new(_: &PluginInfo, _: &mut ()) -> Option<Self> {
151 Some(Self)
152 }
153
154 #[cfg_attr(tarpaulin, skip)]
155 fn run(&mut self, _: &mut (), _: &mut (), _: u32) {}
156 }
157
158 #[derive(FeatureCollection)]
159 struct Features<'a> {
160 _map: LV2Map<'a>,
161 }
162
163 impl State for Stateful {
164 type StateFeatures = Features<'static>;
165
166 #[cfg_attr(tarpaulin, skip)]
167 fn save(&self, _: StoreHandle, _: Features<'static>) -> Result<(), StateErr> {
168 Ok(())
169 }
170
171 #[cfg_attr(tarpaulin, skip)]
172 fn restore(&mut self, _: RetrieveHandle, _: Features<'static>) -> Result<(), StateErr> {
173 Ok(())
174 }
175 }
176
177 #[test]
178 fn test_illegal_paths() {
179 type Descriptor = StateDescriptor<Stateful>;
180 let mut plugin = Stateful;
181
182 assert_eq!(sys::LV2_State_Status_LV2_STATE_ERR_BAD_FLAGS, unsafe {
183 Descriptor::extern_save(
184 std::ptr::null_mut(),
185 None,
186 std::ptr::null_mut(),
187 0,
188 std::ptr::null_mut(),
189 )
190 });
191
192 assert_eq!(sys::LV2_State_Status_LV2_STATE_ERR_BAD_FLAGS, unsafe {
193 Descriptor::extern_restore(
194 std::ptr::null_mut(),
195 None,
196 std::ptr::null_mut(),
197 0,
198 std::ptr::null_mut(),
199 )
200 });
201
202 assert_eq!(sys::LV2_State_Status_LV2_STATE_ERR_UNKNOWN, unsafe {
203 Descriptor::extern_save(
204 std::ptr::null_mut(),
205 None,
206 std::ptr::null_mut(),
207 sys::LV2_State_Flags::LV2_STATE_IS_POD.into(),
208 std::ptr::null_mut(),
209 )
210 });
211
212 assert_eq!(sys::LV2_State_Status_LV2_STATE_ERR_UNKNOWN, unsafe {
213 Descriptor::extern_restore(
214 std::ptr::null_mut(),
215 None,
216 std::ptr::null_mut(),
217 sys::LV2_State_Flags::LV2_STATE_IS_POD.into(),
218 std::ptr::null_mut(),
219 )
220 });
221
222 assert_eq!(sys::LV2_State_Status_LV2_STATE_ERR_NO_FEATURE, unsafe {
223 Descriptor::extern_save(
224 &mut plugin as *mut Stateful as sys::LV2_Handle,
225 None,
226 std::ptr::null_mut(),
227 sys::LV2_State_Flags::LV2_STATE_IS_POD.into(),
228 std::ptr::null_mut(),
229 )
230 });
231
232 assert_eq!(sys::LV2_State_Status_LV2_STATE_ERR_NO_FEATURE, unsafe {
233 Descriptor::extern_restore(
234 &mut plugin as *mut Stateful as sys::LV2_Handle,
235 None,
236 std::ptr::null_mut(),
237 sys::LV2_State_Flags::LV2_STATE_IS_POD.into(),
238 std::ptr::null_mut(),
239 )
240 });
241 }
242}