lv2_core/feature/
cache.rs

1use crate::feature::*;
2use std::collections::{hash_map, HashMap};
3use std::ffi::{c_void, CStr};
4use std::iter::Map;
5
6/// Cache for host features, used in the feature discovery stage.
7///
8/// At initialization time, a raw LV2 plugin receives a null-terminated array containing all requested host features. Obviously, this is not suited for safe Rust code and therefore, it needs an abstraction layer.
9///
10/// Internally, this struct contains a hash map which is filled the raw LV2 feature descriptors. Using this map, methods are defined to identify and retrieve features.
11#[derive(Clone)]
12pub struct FeatureCache<'a> {
13    internal: HashMap<&'a CStr, *const c_void>,
14}
15
16impl<'a> FeatureCache<'a> {
17    /// Construct a cache from the raw features array.
18    ///
19    /// It basically populates a hash map by walking through the array and then creates a `FeatureContainer` with it. However, this method is unsafe since it dereferences a C string to a URI. Also, this method should only be used with the features list supplied by the host since the soundness of the whole module depends on that assumption.
20    ///
21    /// # Safety
22    ///
23    /// This method is unsafe since it needs to dereference the raw feature pointers.
24    pub unsafe fn from_raw(raw: *const *const ::sys::LV2_Feature) -> Self {
25        let mut internal_map = HashMap::new();
26        let mut feature_ptr = raw;
27
28        if !raw.is_null() {
29            while !(*feature_ptr).is_null() {
30                let uri = CStr::from_ptr((**feature_ptr).URI);
31                let data = (**feature_ptr).data as *const c_void;
32                internal_map.insert(uri, data);
33                feature_ptr = feature_ptr.add(1);
34            }
35        }
36
37        Self {
38            internal: internal_map,
39        }
40    }
41
42    /// Evaluate whether this object contains the requested feature.
43    pub fn contains<T: Feature>(&self) -> bool {
44        self.internal.contains_key(T::uri())
45    }
46
47    /// Try to retrieve a feature.
48    ///
49    /// If the feature is not found, this method will return `None`. Since the resulting feature object may have mutable access to the raw data, it will be removed from the cache to avoid aliasing.
50    ///
51    /// You also have to provide the threading class of the feature you want to retrieve.
52    pub fn retrieve_feature<F: Feature, T: FromResolvedFeature<F>>(
53        &mut self,
54        class: ThreadingClass,
55    ) -> Result<T, MissingFeatureError> {
56        T::from_resolved_feature(
57            self.internal
58                .remove(F::uri())
59                .and_then(|ptr| unsafe { F::from_feature_ptr(ptr, class) }),
60        )
61    }
62}
63
64type HashMapIterator<'a> = hash_map::IntoIter<&'a CStr, *const c_void>;
65type DescriptorBuildFn<'a> = fn((&'a CStr, *const c_void)) -> FeatureDescriptor<'a>;
66
67impl<'a> std::iter::IntoIterator for FeatureCache<'a> {
68    type Item = FeatureDescriptor<'a>;
69    type IntoIter = Map<HashMapIterator<'a>, DescriptorBuildFn<'a>>;
70
71    fn into_iter(self) -> Self::IntoIter {
72        self.internal.into_iter().map(|element| {
73            let uri = element.0;
74            let data = element.1;
75            FeatureDescriptor { uri, data }
76        })
77    }
78}
79
80impl<'a> FeatureCollection<'a> for FeatureCache<'a> {
81    fn from_cache(
82        cache: &mut FeatureCache<'a>,
83        _: ThreadingClass,
84    ) -> Result<Self, MissingFeatureError> {
85        Ok(FeatureCache {
86            internal: cache.internal.clone(),
87        })
88    }
89}
90
91/// A trait to allow arbitrary types to be potentially created from feature resolution.
92///
93/// Any type present in a `FeatureCollection` must implement this trait.
94///
95/// For more information, see `FeatureCollection`.
96///
97/// For now this only covers `&T` and `Option<&T>` (where T is a `Feature`), but this may be
98/// extended in the future.
99pub trait FromResolvedFeature<F: Feature>: Sized {
100    fn from_resolved_feature(feature: Option<F>) -> Result<Self, MissingFeatureError>;
101}
102
103impl<F: Feature> FromResolvedFeature<F> for F {
104    fn from_resolved_feature(feature: Option<F>) -> Result<Self, MissingFeatureError> {
105        feature.ok_or_else(|| MissingFeatureError { uri: F::uri() })
106    }
107}
108
109impl<F: Feature> FromResolvedFeature<F> for Option<F> {
110    #[inline]
111    fn from_resolved_feature(feature: Option<F>) -> Result<Self, MissingFeatureError> {
112        Ok(feature)
113    }
114}