#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OperationCategory {
VideoEffect,
AudioEffect,
Transition,
Matte,
}
impl OperationCategory {
#[must_use]
pub fn is_effect(&self) -> bool {
matches!(
self,
OperationCategory::VideoEffect | OperationCategory::AudioEffect
)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ParameterDef {
pub pid: u32,
pub name: String,
pub data_type: String,
}
impl ParameterDef {
#[must_use]
pub fn new(pid: u32, name: String, data_type: String) -> Self {
Self {
pid,
name,
data_type,
}
}
#[must_use]
pub fn is_numeric(&self) -> bool {
matches!(
self.data_type.as_str(),
"Int8"
| "Int16"
| "Int32"
| "Int64"
| "UInt8"
| "UInt16"
| "UInt32"
| "UInt64"
| "Float"
| "Double"
| "Rational"
)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct OperationDef {
pub op_def_id: u32,
pub name: String,
pub category: OperationCategory,
pub parameters: Vec<ParameterDef>,
}
impl OperationDef {
#[must_use]
pub fn new(
op_def_id: u32,
name: String,
category: OperationCategory,
parameters: Vec<ParameterDef>,
) -> Self {
Self {
op_def_id,
name,
category,
parameters,
}
}
#[must_use]
pub fn param_count(&self) -> usize {
self.parameters.len()
}
#[must_use]
pub fn find_param(&self, name: &str) -> Option<&ParameterDef> {
let lower = name.to_lowercase();
self.parameters
.iter()
.find(|p| p.name.to_lowercase() == lower)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct OperationGroup {
pub op_def: OperationDef,
pub length: u64,
pub input_segments: u32,
}
impl OperationGroup {
#[must_use]
pub fn new(op_def: OperationDef, length: u64, input_segments: u32) -> Self {
Self {
op_def,
length,
input_segments,
}
}
#[must_use]
pub fn is_transition(&self) -> bool {
matches!(self.op_def.category, OperationCategory::Transition)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_video_effect_def() -> OperationDef {
OperationDef::new(
1,
"VideoDissolve".into(),
OperationCategory::VideoEffect,
vec![
ParameterDef::new(1, "Level".into(), "Rational".into()),
ParameterDef::new(2, "Reverse".into(), "Boolean".into()),
],
)
}
fn make_transition_def() -> OperationDef {
OperationDef::new(
2,
"Wipe".into(),
OperationCategory::Transition,
vec![ParameterDef::new(1, "Progress".into(), "Rational".into())],
)
}
#[test]
fn test_operation_category_video_is_effect() {
assert!(OperationCategory::VideoEffect.is_effect());
}
#[test]
fn test_operation_category_audio_is_effect() {
assert!(OperationCategory::AudioEffect.is_effect());
}
#[test]
fn test_operation_category_transition_not_effect() {
assert!(!OperationCategory::Transition.is_effect());
}
#[test]
fn test_operation_category_matte_not_effect() {
assert!(!OperationCategory::Matte.is_effect());
}
#[test]
fn test_parameter_def_is_numeric_rational() {
let p = ParameterDef::new(1, "Level".into(), "Rational".into());
assert!(p.is_numeric());
}
#[test]
fn test_parameter_def_is_numeric_boolean() {
let p = ParameterDef::new(2, "Flag".into(), "Boolean".into());
assert!(!p.is_numeric());
}
#[test]
fn test_parameter_def_is_numeric_string() {
let p = ParameterDef::new(3, "Label".into(), "String".into());
assert!(!p.is_numeric());
}
#[test]
fn test_operation_def_param_count() {
let def = make_video_effect_def();
assert_eq!(def.param_count(), 2);
}
#[test]
fn test_operation_def_find_param_found() {
let def = make_video_effect_def();
let p = def.find_param("level");
assert!(p.is_some());
assert_eq!(p.expect("test expectation failed").pid, 1);
}
#[test]
fn test_operation_def_find_param_case_insensitive() {
let def = make_video_effect_def();
assert!(def.find_param("REVERSE").is_some());
}
#[test]
fn test_operation_def_find_param_not_found() {
let def = make_video_effect_def();
assert!(def.find_param("nonexistent").is_none());
}
#[test]
fn test_operation_group_is_transition_false() {
let def = make_video_effect_def();
let grp = OperationGroup::new(def, 100, 1);
assert!(!grp.is_transition());
}
#[test]
fn test_operation_group_is_transition_true() {
let def = make_transition_def();
let grp = OperationGroup::new(def, 50, 2);
assert!(grp.is_transition());
}
#[test]
fn test_operation_group_length() {
let def = make_video_effect_def();
let grp = OperationGroup::new(def, 240, 1);
assert_eq!(grp.length, 240);
}
#[test]
fn test_operation_group_input_segments() {
let def = make_transition_def();
let grp = OperationGroup::new(def, 30, 2);
assert_eq!(grp.input_segments, 2);
}
}