#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EditType {
Cut,
Dissolve,
Wipe,
Key,
}
impl EditType {
#[must_use]
pub fn is_transition(self) -> bool {
!matches!(self, Self::Cut)
}
#[must_use]
pub fn label(self) -> &'static str {
match self {
Self::Cut => "C",
Self::Dissolve => "D",
Self::Wipe => "W",
Self::Key => "K",
}
}
}
#[derive(Debug, Clone)]
pub struct EdlEvent {
pub number: u32,
pub reel: String,
pub edit_type: EditType,
pub source_in: u64,
pub source_out: u64,
pub record_in: u64,
pub record_out: u64,
pub wipe_number: Option<u32>,
pub comment: Option<String>,
}
impl EdlEvent {
#[must_use]
pub fn new(
number: u32,
reel: impl Into<String>,
edit_type: EditType,
source_in: u64,
source_out: u64,
record_in: u64,
record_out: u64,
) -> Self {
Self {
number,
reel: reel.into(),
edit_type,
source_in,
source_out,
record_in,
record_out,
wipe_number: None,
comment: None,
}
}
#[must_use]
pub fn duration_frames(&self) -> u64 {
self.record_out.saturating_sub(self.record_in)
}
#[must_use]
pub fn is_transition(&self) -> bool {
self.edit_type.is_transition()
}
pub fn set_comment(&mut self, comment: impl Into<String>) {
self.comment = Some(comment.into());
}
pub fn set_wipe_number(&mut self, n: u32) {
self.wipe_number = Some(n);
}
}
#[derive(Debug, Clone, Default)]
pub struct EdlEventList {
events: Vec<EdlEvent>,
}
impl EdlEventList {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn add(&mut self, event: EdlEvent) {
self.events.push(event);
}
#[must_use]
pub fn transitions(&self) -> Vec<&EdlEvent> {
self.events.iter().filter(|e| e.is_transition()).collect()
}
#[must_use]
pub fn total_duration_frames(&self) -> u64 {
self.events.iter().map(|e| e.duration_frames()).sum()
}
#[must_use]
pub fn len(&self) -> usize {
self.events.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
#[must_use]
pub fn events(&self) -> &[EdlEvent] {
&self.events
}
#[must_use]
pub fn find(&self, number: u32) -> Option<&EdlEvent> {
self.events.iter().find(|e| e.number == number)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cut_is_not_transition() {
assert!(!EditType::Cut.is_transition());
}
#[test]
fn test_dissolve_is_transition() {
assert!(EditType::Dissolve.is_transition());
}
#[test]
fn test_wipe_is_transition() {
assert!(EditType::Wipe.is_transition());
}
#[test]
fn test_key_is_transition() {
assert!(EditType::Key.is_transition());
}
#[test]
fn test_edit_type_label() {
assert_eq!(EditType::Cut.label(), "C");
assert_eq!(EditType::Dissolve.label(), "D");
assert_eq!(EditType::Wipe.label(), "W");
assert_eq!(EditType::Key.label(), "K");
}
#[test]
fn test_event_duration_frames() {
let ev = EdlEvent::new(1, "R001", EditType::Cut, 0, 100, 1000, 1100);
assert_eq!(ev.duration_frames(), 100);
}
#[test]
fn test_event_duration_zero_when_inverted() {
let ev = EdlEvent::new(1, "R001", EditType::Cut, 0, 0, 50, 30);
assert_eq!(ev.duration_frames(), 0);
}
#[test]
fn test_event_is_transition_cut() {
let ev = EdlEvent::new(1, "R001", EditType::Cut, 0, 25, 0, 25);
assert!(!ev.is_transition());
}
#[test]
fn test_event_is_transition_dissolve() {
let ev = EdlEvent::new(2, "R002", EditType::Dissolve, 0, 12, 0, 12);
assert!(ev.is_transition());
}
#[test]
fn test_event_set_comment() {
let mut ev = EdlEvent::new(1, "R001", EditType::Cut, 0, 10, 0, 10);
assert!(ev.comment.is_none());
ev.set_comment("my note");
assert_eq!(ev.comment.as_deref(), Some("my note"));
}
#[test]
fn test_event_set_wipe_number() {
let mut ev = EdlEvent::new(1, "R001", EditType::Wipe, 0, 10, 0, 10);
ev.set_wipe_number(7);
assert_eq!(ev.wipe_number, Some(7));
}
#[test]
fn test_list_add_and_len() {
let mut list = EdlEventList::new();
assert!(list.is_empty());
list.add(EdlEvent::new(1, "A", EditType::Cut, 0, 25, 0, 25));
assert_eq!(list.len(), 1);
}
#[test]
fn test_list_transitions_only() {
let mut list = EdlEventList::new();
list.add(EdlEvent::new(1, "A", EditType::Cut, 0, 25, 0, 25));
list.add(EdlEvent::new(2, "B", EditType::Dissolve, 0, 12, 25, 37));
list.add(EdlEvent::new(3, "C", EditType::Wipe, 0, 6, 37, 43));
let t = list.transitions();
assert_eq!(t.len(), 2);
}
#[test]
fn test_list_total_duration() {
let mut list = EdlEventList::new();
list.add(EdlEvent::new(1, "A", EditType::Cut, 0, 25, 0, 25));
list.add(EdlEvent::new(2, "B", EditType::Cut, 25, 50, 25, 50));
assert_eq!(list.total_duration_frames(), 50);
}
#[test]
fn test_list_find() {
let mut list = EdlEventList::new();
list.add(EdlEvent::new(42, "X", EditType::Cut, 0, 10, 0, 10));
assert!(list.find(42).is_some());
assert!(list.find(1).is_none());
}
}