use serde::Serialize;
use crate::{Body, Element, Header, Id};
#[derive(Debug, PartialEq, Serialize)]
pub struct MasterElement {
#[serde(flatten)]
header: Header,
children: Vec<ElementTree>,
}
#[derive(Debug, PartialEq, Serialize)]
#[serde(untagged)]
pub enum ElementTree {
Normal(Element),
Master(MasterElement),
}
impl Id {
fn can_be_children_of(&self, other: &Id) -> bool {
!matches!((self, other), (Id::Cluster, Id::Cluster) | (Id::Ebml, _))
}
}
pub fn build_element_trees(elements: &[Element]) -> Vec<ElementTree> {
let mut trees = Vec::<ElementTree>::new();
let mut index = 0;
while index < elements.len() {
let element = &elements[index];
match element.body {
Body::Master => {
let mut size_remaining = element.header.body_size.unwrap_or(usize::MAX);
let mut children = Vec::<Element>::new();
while size_remaining > 0 {
index += 1;
if let Some(next_child) = elements.get(index) {
if !next_child.header.id.can_be_children_of(&element.header.id) {
index -= 1;
break;
}
size_remaining -= if let Body::Master = next_child.body {
next_child.header.header_size
} else {
next_child
.header
.size
.expect("Only Master elements can have unknown size")
};
children.push(next_child.clone());
} else {
break;
}
}
trees.push(ElementTree::Master(MasterElement {
header: element.header.clone(),
children: build_element_trees(&children),
}));
}
_ => {
trees.push(ElementTree::Normal(element.clone()));
}
}
index += 1;
}
trees
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_build_element_trees() {
let elements = [
Element {
header: Header::new(Id::Ebml, 5, 31),
body: Body::Master,
},
Element {
header: Header::new(Id::EbmlVersion, 3, 1),
body: Body::Unsigned(1.into()),
},
Element {
header: Header::new(Id::EbmlReadVersion, 3, 1),
body: Body::Unsigned(1.into()),
},
Element {
header: Header::new(Id::EbmlMaxIdLength, 3, 1),
body: Body::Unsigned(4.into()),
},
Element {
header: Header::new(Id::EbmlMaxSizeLength, 3, 1),
body: Body::Unsigned(8.into()),
},
Element {
header: Header::new(Id::DocType, 3, 4),
body: Body::String("webm".to_string()),
},
Element {
header: Header::new(Id::DocTypeVersion, 3, 1),
body: Body::Unsigned(4.into()),
},
Element {
header: Header::new(Id::DocTypeReadVersion, 3, 1),
body: Body::Unsigned(2.into()),
},
];
let expected = vec![ElementTree::Master(MasterElement {
header: Header::new(Id::Ebml, 5, 31),
children: vec![
ElementTree::Normal(Element {
header: Header::new(Id::EbmlVersion, 3, 1),
body: Body::Unsigned(1.into()),
}),
ElementTree::Normal(Element {
header: Header::new(Id::EbmlReadVersion, 3, 1),
body: Body::Unsigned(1.into()),
}),
ElementTree::Normal(Element {
header: Header::new(Id::EbmlMaxIdLength, 3, 1),
body: Body::Unsigned(4.into()),
}),
ElementTree::Normal(Element {
header: Header::new(Id::EbmlMaxSizeLength, 3, 1),
body: Body::Unsigned(8.into()),
}),
ElementTree::Normal(Element {
header: Header::new(Id::DocType, 3, 4),
body: Body::String("webm".to_string()),
}),
ElementTree::Normal(Element {
header: Header::new(Id::DocTypeVersion, 3, 1),
body: Body::Unsigned(4.into()),
}),
ElementTree::Normal(Element {
header: Header::new(Id::DocTypeReadVersion, 3, 1),
body: Body::Unsigned(2.into()),
}),
],
})];
assert_eq!(build_element_trees(&elements), expected);
}
}