use std::collections::{HashMap, HashSet};
use vst3::Steinberg::Vst::kRootUnitId;
#[derive(Debug)]
pub struct ParamUnits {
units: Vec<ParamUnit>,
unit_id_by_hash: HashMap<u32, i32>,
}
#[derive(Debug)]
pub struct ParamUnit {
pub name: String,
pub parent_id: i32,
}
impl ParamUnits {
pub fn from_param_groups<'a, I>(groups: I) -> Result<Self, &'static str>
where
I: Iterator<Item = (u32, &'a str)> + Clone,
{
let unique_group_names: HashSet<String> = groups
.clone()
.filter_map(|(_, group_name)| {
if !group_name.is_empty() {
Some(group_name)
} else {
None
}
})
.flat_map(|group_name| {
let mut expanded_group = String::new();
let mut expanded_groups = Vec::new();
for component in group_name.split('/') {
if !expanded_group.is_empty() {
expanded_group.push('/');
}
expanded_group.push_str(component);
expanded_groups.push(expanded_group.clone());
}
expanded_groups
})
.collect();
let mut groups_units: Vec<(&str, ParamUnit)> = unique_group_names
.iter()
.map(|group_name| {
(
group_name.as_str(),
ParamUnit {
name: match group_name.rfind('/') {
Some(sep_pos) => group_name[sep_pos + 1..].to_string(),
None => group_name.to_string(),
},
parent_id: kRootUnitId,
},
)
})
.collect();
groups_units.sort_by_key(|(group_name_l, _)| *group_name_l);
let vst3_unit_id_by_group_name: HashMap<&str, i32> = groups_units
.iter()
.enumerate()
.map(|(unit_id, (group_name, _))| (*group_name, unit_id as i32 + 1))
.collect();
for (group_name, unit) in &mut groups_units {
if let Some(sep_pos) = group_name.rfind('/') {
let parent_group_name = &group_name[..sep_pos];
let parent_unit_id = *vst3_unit_id_by_group_name
.get(parent_group_name)
.ok_or("Missing parent group")?;
unit.parent_id = parent_unit_id;
}
}
let unit_id_by_hash: HashMap<u32, i32> = groups
.map(|(param_hash, group_name)| {
if group_name.is_empty() {
(param_hash, kRootUnitId)
} else {
(param_hash, vst3_unit_id_by_group_name[group_name])
}
})
.collect();
let units: Vec<ParamUnit> = groups_units.into_iter().map(|(_, unit)| unit).collect();
Ok(Self {
units,
unit_id_by_hash,
})
}
pub fn len(&self) -> usize {
self.units.len()
}
pub fn info(&self, index: usize) -> Option<(i32, &ParamUnit)> {
let info = self.units.get(index)?;
Some((index as i32 + 1, info))
}
pub fn get_vst3_unit_id(&self, param_hash: u32) -> Option<i32> {
self.unit_id_by_hash.get(¶m_hash).copied()
}
}