Replace Schema types with a FromEbml trait on the Element type
simplify lifetimes
This commit is contained in:
parent
972a88c35b
commit
cdcff869aa
7 changed files with 48 additions and 49 deletions
|
@ -4,9 +4,7 @@ use std::env::args;
|
|||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use lab_ebml::Schema;
|
||||
use lab_ebml::webm::SimpleBlock;
|
||||
use lab_ebml::webm::Webm;
|
||||
use lab_ebml::webm::{ parse_webm, SimpleBlock };
|
||||
use lab_ebml::webm::WebmElement::*;
|
||||
|
||||
pub fn main() {
|
||||
|
@ -19,7 +17,7 @@ pub fn main() {
|
|||
|
||||
file.read_to_end(&mut buffer).expect("Reading file contents");
|
||||
|
||||
for element in Webm.parse(buffer.as_slice()) {
|
||||
for element in parse_webm(buffer.as_slice()) {
|
||||
match element {
|
||||
// suppress printing byte arrays
|
||||
Tracks(slice) => println!("Tracks[{}]", slice.len()),
|
||||
|
|
|
@ -5,7 +5,6 @@ extern crate lab_ebml;
|
|||
use futures::future::FutureResult;
|
||||
use futures::stream::{iter, Stream};
|
||||
use lab_ebml::chunk::{Chunk, WebmStream, ChunkingError};
|
||||
use lab_ebml::Schema;
|
||||
use lab_ebml::timecode_fixer::ChunkStream;
|
||||
use lab_ebml::webm::*;
|
||||
use hyper::{Get, StatusCode};
|
||||
|
@ -29,9 +28,9 @@ impl Service for WebmServer {
|
|||
fn call(&self, req: Request) -> Self::Future {
|
||||
let response = match (req.method(), req.path()) {
|
||||
(&Get, "/loop") => {
|
||||
let stream: BodyStream<Vec<u8>> = iter(Webm.parse(SRC_FILE).into_iter().map(|x| Ok(x)))
|
||||
let stream: BodyStream<Vec<u8>> = iter(parse_webm(SRC_FILE).into_iter().map(|x| Ok(x)))
|
||||
.chunk_webm()
|
||||
.chain(iter(Webm.parse(SRC_FILE).into_iter().map(|x| Ok(x))).chunk_webm())
|
||||
.chain(iter(parse_webm(SRC_FILE).into_iter().map(|x| Ok(x))).chunk_webm())
|
||||
.fix_timecodes()
|
||||
.map_err(|err| match err {
|
||||
ChunkingError::IoError(io_err) => hyper::Error::Io(io_err),
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
extern crate lab_ebml;
|
||||
|
||||
use std::io::{Cursor, stdout, Write};
|
||||
use lab_ebml::Schema;
|
||||
use lab_ebml::webm::*;
|
||||
use lab_ebml::webm::WebmElement::*;
|
||||
use lab_ebml::timecode_fixer::TimecodeFixer;
|
||||
|
@ -15,7 +14,7 @@ pub fn main() {
|
|||
|
||||
let mut reading_head = true;
|
||||
|
||||
for element in Webm.parse(SRC_FILE) {
|
||||
for element in parse_webm(SRC_FILE) {
|
||||
match element {
|
||||
Cluster => reading_head = false,
|
||||
// TODO: skip elements not required for streaming
|
||||
|
|
39
src/ebml.rs
39
src/ebml.rs
|
@ -2,6 +2,7 @@ use bytes::{BigEndian, ByteOrder, BufMut};
|
|||
use std::error::Error as ErrorTrait;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
use std::io::{Cursor, Error as IoError, ErrorKind, Result as IoResult, Write, Seek, SeekFrom};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub const EBML_HEAD_ID: u64 = 0x0A45DFA3;
|
||||
pub const DOC_TYPE_ID: u64 = 0x0282;
|
||||
|
@ -214,20 +215,21 @@ pub fn encode_integer<T: Write>(tag: u64, value: u64, output: &mut T) -> IoResul
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Ebml<S, T>(pub S, pub T);
|
||||
pub struct Ebml<Source, Element> {
|
||||
pub source: Source,
|
||||
_marker: PhantomData<fn() -> Element>
|
||||
}
|
||||
|
||||
pub trait Schema<'a> {
|
||||
type Element: 'a;
|
||||
pub trait FromEbml<'b>: Sized {
|
||||
fn should_unwrap(element_id: u64) -> bool;
|
||||
fn decode(element_id: u64, bytes: &'b[u8]) -> Result<Self, Error>;
|
||||
|
||||
fn should_unwrap(&self, element_id: u64) -> bool;
|
||||
fn decode<'b: 'a>(&self, element_id: u64, bytes: &'b[u8]) -> Result<Self::Element, Error>;
|
||||
|
||||
fn decode_element<'b: 'a>(&self, bytes: &'b[u8]) -> Result<Option<(Self::Element, usize)>, Error> {
|
||||
fn decode_element(bytes: &'b[u8]) -> Result<Option<(Self, usize)>, Error> {
|
||||
match decode_tag(bytes) {
|
||||
Ok(None) => Ok(None),
|
||||
Err(err) => Err(err),
|
||||
Ok(Some((element_id, payload_size_tag, tag_size))) => {
|
||||
let should_unwrap = self.should_unwrap(element_id);
|
||||
let should_unwrap = Self::should_unwrap(element_id);
|
||||
|
||||
let payload_size = match (should_unwrap, payload_size_tag) {
|
||||
(true, _) => 0,
|
||||
|
@ -241,7 +243,7 @@ pub trait Schema<'a> {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
match self.decode(element_id, &bytes[tag_size..element_size]) {
|
||||
match Self::decode(element_id, &bytes[tag_size..element_size]) {
|
||||
Ok(element) => Ok(Some((element, element_size))),
|
||||
Err(error) => Err(error)
|
||||
}
|
||||
|
@ -249,8 +251,11 @@ pub trait Schema<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse<T>(self, source: T) -> Ebml<Self, T> where Self: Sized {
|
||||
Ebml(self, source)
|
||||
fn parse<T>(source: T) -> Ebml<T, Self> {
|
||||
Ebml {
|
||||
source: source,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,21 +403,17 @@ mod tests {
|
|||
assert_eq!(decode_uint(&[0x80,0,0,0,0,0,0,1]), Ok(9223372036854775809));
|
||||
}
|
||||
|
||||
struct Dummy;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct GenericElement(u64, usize);
|
||||
|
||||
impl<'a> Schema<'a> for Dummy {
|
||||
type Element = GenericElement;
|
||||
|
||||
fn should_unwrap(&self, element_id: u64) -> bool {
|
||||
impl<'a> FromEbml<'a> for GenericElement {
|
||||
fn should_unwrap(element_id: u64) -> bool {
|
||||
match element_id {
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn decode<'b: 'a>(&self, element_id: u64, bytes: &'b[u8]) -> Result<GenericElement, Error> {
|
||||
fn decode(element_id: u64, bytes: &'a[u8]) -> Result<GenericElement, Error> {
|
||||
match element_id {
|
||||
_ => Ok(GenericElement(element_id, bytes.len()))
|
||||
}
|
||||
|
@ -421,7 +422,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn decode_sanity_test() {
|
||||
let decoded = Dummy.decode_element(TEST_FILE);
|
||||
let decoded = GenericElement::decode_element(TEST_FILE);
|
||||
assert_eq!(decoded, Ok(Some((GenericElement(0x0A45DFA3, 31), 43))));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
use std::marker::PhantomData;
|
||||
use ebml::*;
|
||||
|
||||
pub struct EbmlIterator<'b, T: Schema<'b>> {
|
||||
schema: T,
|
||||
pub struct EbmlIterator<'b, T: FromEbml<'b>> {
|
||||
slice: &'b[u8],
|
||||
position: usize,
|
||||
_marker: PhantomData<fn() -> T>
|
||||
}
|
||||
|
||||
impl<'b, S: Schema<'b>> IntoIterator for Ebml<S, &'b[u8]> {
|
||||
type Item = S::Element;
|
||||
type IntoIter = EbmlIterator<'b, S>;
|
||||
impl<'b, E: FromEbml<'b>> IntoIterator for Ebml<&'b[u8], E> {
|
||||
type Item = E;
|
||||
type IntoIter = EbmlIterator<'b, E>;
|
||||
|
||||
fn into_iter(self) -> EbmlIterator<'b, S>
|
||||
fn into_iter(self) -> EbmlIterator<'b, E>
|
||||
{
|
||||
EbmlIterator {
|
||||
schema: self.0,
|
||||
slice: self.1,
|
||||
position: 0
|
||||
slice: self.source,
|
||||
position: 0,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T: Schema<'b>> Iterator for EbmlIterator<'b, T> {
|
||||
type Item = T::Element;
|
||||
impl<'b, T: FromEbml<'b>> Iterator for EbmlIterator<'b, T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T::Element> {
|
||||
match self.schema.decode_element(&self.slice[self.position..]) {
|
||||
fn next(&mut self) -> Option<T> {
|
||||
match Self::Item::decode_element(&self.slice[self.position..]) {
|
||||
Err(_) => None,
|
||||
Ok(None) => None,
|
||||
Ok(Some((element, element_size))) => {
|
||||
|
|
|
@ -8,7 +8,7 @@ mod iterator;
|
|||
pub mod timecode_fixer;
|
||||
pub mod webm;
|
||||
|
||||
pub use ebml::{Error, Schema};
|
||||
pub use ebml::{Error, FromEbml};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
15
src/webm.rs
15
src/webm.rs
|
@ -10,7 +10,10 @@ const TRACKS_ID: u64 = 0x0654AE6B;
|
|||
const CLUSTER_ID: u64 = 0x0F43B675;
|
||||
const TIMECODE_ID: u64 = 0x67;
|
||||
const SIMPLE_BLOCK_ID: u64 = 0x23;
|
||||
pub struct Webm;
|
||||
|
||||
pub fn parse_webm<'a, T: 'a>(source: T) -> Ebml<T, WebmElement<'a>> {
|
||||
WebmElement::parse(source)
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub struct SimpleBlock<'b> {
|
||||
|
@ -35,10 +38,8 @@ pub enum WebmElement<'b> {
|
|||
Unknown(u64)
|
||||
}
|
||||
|
||||
impl<'a> Schema<'a> for Webm {
|
||||
type Element = WebmElement<'a>;
|
||||
|
||||
fn should_unwrap(&self, element_id: u64) -> bool {
|
||||
impl<'b> FromEbml<'b> for WebmElement<'b> {
|
||||
fn should_unwrap(element_id: u64) -> bool {
|
||||
match element_id {
|
||||
// Segment
|
||||
SEGMENT_ID => true,
|
||||
|
@ -47,7 +48,7 @@ impl<'a> Schema<'a> for Webm {
|
|||
}
|
||||
}
|
||||
|
||||
fn decode<'b: 'a>(&self, element_id: u64, bytes: &'b[u8]) -> Result<WebmElement<'b>, Error> {
|
||||
fn decode(element_id: u64, bytes: &'b[u8]) -> Result<WebmElement<'b>, Error> {
|
||||
match element_id {
|
||||
EBML_HEAD_ID => Ok(WebmElement::EbmlHead),
|
||||
VOID_ID => Ok(WebmElement::Void),
|
||||
|
@ -131,7 +132,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn decode_webm_test1() {
|
||||
let mut iter = Webm.parse(TEST_FILE).into_iter();
|
||||
let mut iter = parse_webm(TEST_FILE).into_iter();
|
||||
|
||||
// test that we match the structure of the test file
|
||||
assert_eq!(iter.next(), Some(WebmElement::EbmlHead));
|
||||
|
|
Loading…
Reference in a new issue